FParsec中的同时匹配

时间:2011-12-16 14:53:26

标签: bnf fparsec

如果我正在尝试将以下内容解析为linesfields。行由'\n'分隔,字段由'|'分隔。

abcd|efgh|ijkl
mnopq\|rst|uvwxy
za|bcd
efg|hijk|lmnop

我可以定义以下内容:

let displayCharacter = satisfy (fun c -> ' ' <= c && c <= '~')
let escapedDC = pchar '\\' >>. displayCharacter
let test1 = 
    run (manyChars (escapedDC <|> displayCharacter)) "asdf\|efgh|ijkl"
    // Success: "asdf|efgh|ijkl"

let fields = sepBy (manyChars (escapedDC <|> displayCharacter)) (pchar '|')无法从字段中排除'|'。这些分隔符是上下文敏感的,所以我想避免将它们硬编码到displayCharacter,因为'|'是一个显示字符,但在某些情况下可能需要转义。

如果我尝试使用field定义单个manyCharsTill,那么我需要考虑anyOf "|\n"行上的最后一个元素,但这会读入所有行一个line

在某些情况下,我可能还有'|'以外的其他subdelimiters。因此,为每种情况定义displayCharacter和escapedDC的版本似乎很麻烦。相反,使用超前功能似乎更清晰。或者也许是一个名为both的解析器,它在某种程度上需要同时匹配两个解析器。

manyCharsSepBy (escapedDC <|> displayCharacter) (pchar '|')

let contextualDisplayCharacter1 = both displayCharacter (satisfy ((<>) '|'))

有没有更简单的方法来实现这一目标?也许只是我隐含的BNF存在缺陷 - 如果修复,会很容易翻译吗?

============

这是我能想到的最好的,但我想知道专家是否是最灵活的方式。

let displayCharacter (excludeDelimiters : string) = satisfy (fun c -> ' ' <= c && c <= '~' && not (Seq.exists ((=) c) excludeDelimiters))
let escapedDisplayCharacter = pchar '\\' >>. displayCharacter ""

let field = 
    manyChars (escapedDisplayCharacter <|> displayCharacter "|")

0 个答案:

没有答案