【问题标题】:Split string on first occurrence of number or comma在第一次出现数字或逗号时拆分字符串
【发布时间】:2020-07-27 07:31:45
【问题描述】:

我是一名对学习 F# 感兴趣的 C# 开发人员。我有一个非常简单的问题:在第一次出现数字或逗号时将字符串分成两部分。显然,天真的实现是:

let parts = text.Split([| ','; '0'; '1'; '2'; '3'; '4'; '5'; '6'; '7'; '8'; '9' |], 2)

但是,这看起来不是很实用,并且性能可能很糟糕。我想知道,有没有更好的方法在 F# 中做到这一点?我在看Active patterns,但不知道如何正确使用它们。还是我应该使用“好旧的”正则表达式?

【问题讨论】:

    标签: f#


    【解决方案1】:

    如果标准 .NET 库操作没有发生变异,那么它们并没有什么不正常的地方。 Split 操作接受一个字符串并返回一个字符串集合,因此它的功能非常完善。

    您的代码的一个问题是,如果字符串中有多个数字或空格,Split 会将字符串拆分为多个部分,而不仅仅是 2,因此您可能希望使用 IndexOf 来查找第一个的索引分割字符,然后用它来分割字符串。

    在这种情况下,我不会使用任何复杂的东西,比如活动模式和正则表达式。下面很清楚:

    let splitString (s:string) =
      let i = s.IndexOfAny("0123456789 ,".ToCharArray())
      if i < 0 then None 
      else Some(s.Substring(0, i), s.Substring(i+1))
    

    如果这是一个更复杂的规则处理系统的一部分,你有 10 多个这样的规则需要编码,那么使用活动模式是值得的,但对于单个函数,简单是最好的!

    【讨论】:

    • 除了您的回答内容丰富之外,我还要特别感谢.ToCharArray 的小技巧。它是永远改变程序员生活的那些 sn-ps 代码之一 :)
    • @Storm 感谢您的好评! ToCharArray 把戏只是显示了我是多么的懒惰:-)
    【解决方案2】:

    可以使用ToCharArray方法获取字符串的char数组,然后使用Array.tryFindIndex函数查找分隔符,最后使用Substring方法将字符串拆分为两部分。

    代码如下:

    let str = "hello,world"
    str.ToCharArray ()
    |> Array.tryFindIndex (fun ch -> ch = ',' || (ch >= '0' && ch <= '9'))
    |> function | Some i -> str.Substring(0, i), str.Substring(i + 1)
                | None -> str, ""
    

    我真的不知道你为什么要在这里使用主动模式。但是,当您有多种分隔字符串的方法时,使用活动模式可能会很有用。它可以帮助代码更具可读性,例如:

    // Write some Active Patterns:
    
    let split condition (str: string) =
        str.ToCharArray ()
        |> Array.tryFindIndex condition
        |> Option.map (fun i -> str.Substring(0, i), str.Substring(i + 1))
    
    let (| SeparatedByCommaOrDigits | _ |) str =
        str |> split (fun ch -> ch = ',' || (ch >= '0' && ch <= '9'))
        
    let (| SeparatedByDotOrUnderscrore | _ |) str =
        str |> split (fun ch -> ch = '.' || ch = '_')
    
    // The beauty of Active Patterns:
    
    let str = "hel,lo_world"
    match str with
    | SeparatedByCommaOrDigits (a, b) -> printfn "%s\n%s" a b
    | SeparatedByDotOrUnderscrore (a, b) -> printfn "%s\n%s" a b
    | _ -> printfn "invalid"
    

    【讨论】:

      【解决方案3】:

      我会为此使用“旧的”正则表达式:

      open System.Text.RegularExpressions
      
      let parts text =
          let a = Regex.Split(text,"[,0-9](.+)")
          if a.Length < 2 then None else Some (a.[0],a.[1])
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-10-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-08-12
        • 1970-01-01
        相关资源
        最近更新 更多