如何在FSharp中提取字符串的中间部分?

时间:2010-09-20 15:45:30

标签: string f# pattern-matching

如果引用,我想使用FSharp提取字符串的中间部分,类似这样:

let middle =
    match original with
    | "\"" + mid + "\"" -> mid
    | all -> all

但由于模式表达式中的中缀运算符+,它不起作用。我怎样才能提取这个?

5 个答案:

答案 0 :(得分:12)

我认为没有任何直接支持,但您当然可以编写活动模式。活动模式允许您实现自己的代码,这些代码将作为模式匹配的一部分运行,您可以提取&返回部分值。

以下是带有两个参数(前缀和后缀字符串)的模式,如果给定输入以指定字符串开头/结尾,则成功。模式不完整(可能失败),因此我们将使用|Name|_|语法,它将需要返回选项值:

let (|Middle|_|) prefix postfix (input:string) =
  // Check if the string starts with 'prefix', ends with 'postfix' and 
  // is longer than the two (meaning that it contains some middle part)
  if input.StartsWith(prefix) && input.EndsWith(postfix) && 
     input.Length >= (prefix.Length + postfix.Length) then 
    // Strip the prefix/postfix and return 'Some' to indicate success
    let len = input.Length - prefix.Length - postfix.Length
    Some(input.Substring(prefix.Length, len))
  else None // Return 'None' - string doesn't match the pattern

现在我们可以在模式匹配中使用Middle(例如,在使用match时):

match "[aaa]"  with
| Middle "[" "]" mid -> mid
| all -> all

答案 1 :(得分:4)

参与化active patterns救援!

let (|HasPrefixSuffix|_|) (pre:string, suf:string) (s:string) =
    if s.StartsWith(pre) then
        let rest = s.Substring(pre.Length)
        if rest.EndsWith(suf) then
            Some(rest.Substring(0, rest.Length - suf.Length))
        else
            None
    else
        None

let Test s =
    match s with
    | HasPrefixSuffix("\"","\"") inside -> 
        printfn "quoted, inside is: %s" inside
    | _ -> printfn "not quoted: %s" s

Test "\"Wow!\""
Test "boring"

答案 2 :(得分:3)

...或者只使用普通的旧正则表达式

let Middle input =
    let capture = Regex.Match(input, "\"([^\"]+)\"")
    match capture.Groups.Count with
    | 2 -> capture.Groups.[1].Value
    | _ -> input

答案 3 :(得分:2)

模式的语法有限 - 你不能只使用任何表达式。在这种情况下,我只使用if / then / else:

let middle (s:string) =
  if s.[0] = '"' && s.[s.Length - 1] = '"' && s.Length >= 2 then 
    s.Substring(1,s.Length - 2)
  else s

如果用一个静态已知的开头和结尾抓住一个字符串的中间部分你会做很多事情,那么你总是可以像Tomas建议的那样使用一个活动模式。

答案 4 :(得分:0)

不确定这是多么有效:

let GetQuote (s:String) (q:char) = 
        s 
        |> Seq.skip ((s |> Seq.findIndex (fun c -> c = q))+1)
        |> Seq.takeWhile (fun c-> c <> q) 
        |> Seq.fold(fun acc c -> String.Format("{0}{1}", acc, c)) ""

或者使用Substring代替折叠:

let GetQuote2 (s:String) (q:char)  = 
    let isQuote = (fun c -> c = q)
    let a = (s |> Seq.findIndex isQuote)+1
    let b = ((s |> Seq.take(a) |> Seq.findIndex isQuote)-1)
    s.Substring(a,b);

这些将在字符串中的任何位置获得引用文本的第一个实例,例如“Hello [World]” - &gt; “世界”