Одновременный матч в FParsec - PullRequest
1 голос
/ 16 декабря 2011

Если я пытаюсь разобрать следующее в lines и fields. Строки ограничены '\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.

Возможно, у меня есть и другие дополнительные ограничители, кроме '|', которые поддерживаются в определенных контекстах. По этой причине кажется беспорядочным определять версии 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 "|")
...