2015-07-16 5 views
3

Я пытаюсь разобрать одну строку, которая содержит строки, разделенные разделителями, в последовательность этих строк. Он должен иметь возможность иметь любой символ в строках, если поле содержит разделитель, ему нужны двойные кавычки. Чтобы иметь двойные кавычки в таком поле, двойные кавычки ускользают.Parboiled2 grammar для синтаксического анализа escaped CSV line

Я использовал это в качестве отправной точки: https://github.com/sirthias/parboiled2/blob/695ee6603359cfcb97734edf6dd1d27383c48727/examples/src/main/scala/org/parboiled2/examples/CsvParser.scala

Моя грамматика выглядит следующим образом:

class CsvParser(val input: ParserInput, val delimiter: String = ",") extends Parser { 
    def line: Rule1[Seq[String]] = rule {record ~ EOI} 
    def record = rule(oneOrMore(field).separatedBy(delimiter)) 

    def QUOTE = "\"" 
    def ESCAPED_QUOTE = "\\\"" 
    def DELIMITER_QUOTE = delimiter+"\"" 
    def WS = " \t".replace(delimiter, "") 

    def field = rule{whiteSpace ~ ((QUOTE ~ escapedField ~ QUOTE) | unquotedField) ~ whiteSpace} 
    def escapedField = rule { capture(zeroOrMore(noneOf(QUOTE) | ESCAPED_QUOTE)) ~> (_.replace(ESCAPED_QUOTE, QUOTE)) } 
    def unquotedField = rule { capture(zeroOrMore(noneOf(DELIMITER_QUOTE))) } 
    def whiteSpace = rule(zeroOrMore(anyOf(WS))) 
} 

Когда я называю его "quote\"key",1,2 я получаю Invalid input 'k', expected whiteSpace, ',' or 'EOI' (line 1, column 9)

Что я делаю неправильно? Как мне отладить это? (И в качестве бонусного вопроса: как расширить грамматику, чтобы разделитель мог быть кратным символам, например ##?)

Спасибо!

ответ

2

Parboiled2, похоже, выполняет правила без обратного отслеживания.

В данном конкретном случае

def escapedField = rule { capture(zeroOrMore(noneOf(QUOTE) | ESCAPED_QUOTE)) ~> (_.replace(ESCAPED_QUOTE, QUOTE)) } 

noneOf(QUOTE) захватывает \ из \ «а затем возвращается, вместо возвратов и пытается захватить полный \».

Ошибка решается с помощью

def escapedField = rule { capture(ESCAPED_QUOTE | zeroOrMore(noneOf(QUOTE))) ~> (_.replace(ESCAPED_QUOTE, QUOTE)) } 

 Смежные вопросы

  • Нет связанных вопросов^_^