在 F# 中跨新行标记换行符和字符串文字
Tokenize newline and string literals across new line in 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
标记,但我想:
- 捕获我匹配的每个新行。
- 将多行字符串捕获为字符串文字。
我发现了类似的问题,但我什至无法捕捉新行。我尝试使用 RegexOptions
(Singleline
和 Multiline
)的各种设置将第一个模式添加到第二个模式(之前没有拆分行),但我没有匹配新行就结束了.
分割线似乎是您的 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
跳过三引号块中的分隔符。
我正在使用 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
标记,但我想:
- 捕获我匹配的每个新行。
- 将多行字符串捕获为字符串文字。
我发现了类似的问题,但我什至无法捕捉新行。我尝试使用 RegexOptions
(Singleline
和 Multiline
)的各种设置将第一个模式添加到第二个模式(之前没有拆分行),但我没有匹配新行就结束了.
分割线似乎是您的 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
跳过三引号块中的分隔符。