2015-08-27 6 views
0

Я пытаюсь написать синтаксический анализатор, который может анализировать пары значений ключей, которые могут различаться по типу данных значения.fparsec пар синтаксического анализа пар с разными типами данных

KEY1:1,2,3

KEY2:abc

KEY3:123

С помощью следующего кода

open FParsec 
type UserState = unit 
type Parser<'t> = Parser<'t,UserState> 

let str s = pstring s 
let str_ws s = str s .>> spaces 
let stringLiteral : Parser<_> = manyChars (noneOf "\">") 

let numList : Parser<_> = sepBy1 (pint32) (str ",") 

let parseHeader inner header = str header >>. str ":" >>. inner 
let parseKvps = 
    let strHeader header = parseHeader stringLiteral header .>> newline 
    let numListHeader header = parseHeader numList header .>> newline 
    let numHeader header = parseHeader pint32 header .>> newline 

    let rest = parse { 
     let! key1 = numListHeader "KEY1" 
     let! key2 = strHeader "KEY2" 
     let! key3 = numHeader "KEY3" 
     return key1,key2,key3 
    } 
    rest 

let kvps = "KEY1:1,2,3\nKEY2:abc\nKEY3:123" 
run parseKvps kvps 

Над дает следующее сообщение об ошибке:

val it : ParserResult<(int32 list * string * int32),unit> = 
    Failure: 
Error in Ln: 3 Col: 9 
KEY3:123 
     ^
Note: The error occurred at the end of the input stream. 
Expecting: any char not in ‘">’ or newline 

Я думаю, это что-то делать с numList анализатором, потому что принимая первый ключ из работ, как ожидается.

Цените любую помощь! Заранее спасибо!

ответ

0

Третий парсер не работает, потому что FParsec не нашел нужного \n в конце.

Есть несколько вариантов, чтобы решить эту проблему:

  1. Сделайте ваши данные действительны при добавлении \n к потоку:

    let kvps = "KEY1:1,2,3\nKEY2:abc\nKEY3:123\n" 
    

    Даунсайд: изменение потока источника хорош только для тестирования, не для реального приложения.

  2. Сделать .>> newline дополнительно:

    .>> (optional newline) 
    

    Даунсайд: Это может привести к ошибкам, когда две клавиши на одной и той же исходной линии пытались разобрать.

  3. Попробуйте использовать eof в качестве возможной альтернативы newline


Кроме того, примечание стороны. Ваш код, кажется, очень трудно поддерживать. Подумайте, что произойдет, если ключи произойдут в неправильном порядке в исходной строке или добавлен новый ключ в ходе разработки вашего приложения.

Отметьте this и this ответы для получения более подробной информации.

+0

добавление '\ n' не работает, к сожалению. Я пробовал это и продолжаю получать ту же ошибку. Он отлично работает, если я удалю первый ключ 'KEY1', что-то связанное с парсером int list. Просто не знаю, как это понять. – Pavel

+0

@Pavel, ваш 'stringLiteral' также написан неточно, поскольку он переполняет конец строки. Возможно, вы имели в виду '(restOfLine false)' вместо этого? – bytebuster