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,

Другие вопросы по тегам