在F#中对新行标记换行符和字符串文字

时间:2015-06-23 19:17:03

标签: regex parsing f#

我正在使用 F#开发TOML解析器。在我目前的解决方案中,我使用以下方式拆分行:


let regex s = new Regex(s, RegexOptions.Compiled)
let linesRe = regex @"\r\n|\r|\n"

和lex令牌:


let tokenRe = regex @"((?(\d+|\w+|(""\w+"")|\[|\]|.|=))\s*)*"
let tokenizeLine (s: string) =
  [for x in tokenRe.Match(s).Groups.["token"].Captures do
    let token =
      match x.Value with
      | "[" -> OPENBR
      // omissis...
      | s when isStringLiteral s -> STR (s.Substring(1, s.Length-2))
      | s -> ID s
    yield token]

通过这种方式,我将无法处理定义为:

的多行字符串

lines = '''
The first newline is
trimmed in raw strings.
   All other whitespace
   is preserved.
'''

现在我在每一行添加NEWLINE令牌,但我想:

  1. 捕获我匹配的每一个新行。
  2. 将多行字符串捕获为字符串文字。
  3. 我发现了类似的问题,但我甚至无法捕获新的线条。我尝试使用RegexOptionsSinglelineMultiline)的各种设置将第一个模式添加到第二个模式(之前没有拆分线),但我结束时没有匹配新行

1 个答案:

答案 0 :(得分:2)

分割线似乎是TOML文件的第一遍或预处理过程,使用Mark Seemann建议的FParsec等解析器库可能更容易。

另一个选择是使用简单的状态机来分割行,例如

let split separator (s:string) =
    let values = ResizeArray<_>()
    let rec gather start i qs =
        let add () = s.Substring(start,i-start) |> values.Add
        if i = s.Length then add()
        elif s.[i] = '"' && qs = 2 then inTripleQuotes start (i+1) 0
        elif s.[i] = '"' then gather start (i+1) (qs+1)
        elif s.[i] = separator then add(); gather (i+1) (i+1) 0
        else gather start (i+1) 0
    and inTripleQuotes start i qs =
        if s.[i] = '"' && qs = 2 then gather start (i+1) 0
        elif s.[i] = '"' then inTripleQuotes start (i+1) (qs+1)
        else inTripleQuotes start (i+1) 0
    gather 0 0 0
    values.ToArray()

split '\n' text

在上面的split函数中,我使用了2个相互递归的函数,gather进行扫描,直到达到分隔符,inTripleQuotes跳过三引号块中的分隔符。