FParsec - как разобрать строки, разделенные трубами?
Я использую FParsec для написания небольшого парсера в режиме org, для развлечения, и у меня возникли небольшие проблемы с анализом строки таблицы в списке строк. Мой текущий код выглядит так:
let parseRowEntries :Parser<RowEntries, unit> =
let skipInitialPipe = skipChar '|'
let notaPipe = function
| '|' -> false
| _ -> true
let pipeSep = pchar '|'
skipInitialPipe >>. sepEndBy (many1Satisfy notaPipe) pipeSep
|>> RowEntries
Это работает нормально, пока вы не проанализируете строку |blah\n|blah\n|blah|
который должен потерпеть неудачу из-за символа новой строки. К сожалению просто делая \n
ложь в notaPipe
условие заставляет синтаксический анализатор останавливаться после первого "бла" и говорить, что он был успешно проанализирован. Я хочу, чтобы manySatisfy выполнял синтаксический анализ (почти) любых символов, останавливаясь на канале, не разбирая символы новой строки (и, вероятно, символ eof).
Я пытался использовать charsTillString
но это также просто останавливает синтаксический анализ первого канала без ошибок.
1 ответ
Если я правильно понял вашу спецификацию, это должно сработать:
let parseOneRow :Parser<_, unit> =
let notaPipe = function
| '|' -> false
| '\n' -> false
| _ -> true
let pipe = pchar '|'
pipe >>. manyTill (many1Satisfy notaPipe .>> pipe) (skipNewline <|> eof)
let parseRowEntries :Parser<_, unit> =
many parseOneRow
run parseRowEntries "|row|with|four|columns|\n|second|row|"
// Success: [["row"; "with"; "four"; "columns"]; ["second"; "row"]]
Структура состоит в том, что каждая строка начинается с трубы, а затем сегменты в строке концептуально row|
, with|
, и так далее. .>>
комбинатор отбрасывает трубу. Причина, по которой часть строки доходит до skipNewline
вместо newline
потому что eof
парсер возвращает unit
так что нам нужен парсер, который ожидает переводы строки и возврат unit
, Это skipNewline
синтаксический анализатор.
Я попытался добавить новые строки там, где они не принадлежат (например, перед каналами), и это приводит к тому, что этот синтаксический анализатор дает сбой точно так, как должен. Также происходит сбой, если столбец пуст (то есть два символа канала появляются рядом, как ||
), что я думаю, это то, что вы хотите. Если вы хотите разрешить пустые строки, просто используйте manySatisfy
вместо many1Satisfy
,