2012-06-20 3 views
2

Я пытаюсь разобрать текстовый файл с помощью комбинаторов парсера. Я хочу захватить индекс и текст в классе под названием Example. Вот тест, показывающий форму на входном файле:Использование комбинаторов парсера для сопоставления строк текста

object Test extends ParsComb with App { 
    val input = """ 
0) 
blah1 
blah2 
blah3 
1) 
blah4 
blah5 
END 
""" 
    println(parseAll(examples, input)) 
} 

И вот моя попытка, что не работает:

import scala.util.parsing.combinator.RegexParsers 

case class Example(index: Int, text: String) 

class ParsComb extends RegexParsers { 
    def examples: Parser[List[Example]] = rep(divider~example) ^^ 
              {_ map {case d ~ e => Example(d,e)}} 
    def divider: Parser[Int]   = "[0-9]+".r <~ ")" ^^ (_.toInt) 
    def example: Parser[String]  = ".*".r <~ (divider | "END") 
} 

Он терпит неудачу с:

[4.1] failure: `END' expected but `b' found 

blah2 

^ 

Я просто начиная с них, поэтому я не очень понимаю, что я делаю. Я думаю, что проблема может быть с регулярным выражением ".*".r, не выполняющим многострочные строки. Как я могу изменить это так, чтобы он правильно разбирался?

ответ

5
  • Что означает сообщение об ошибке означает?

Согласно вашему определению грамматики, ".*".r <~ (divider | "END"), вы сказали анализатору, что example должен затем либо с помощью divider или END. После парсинга blah1 анализатор попытался найти divider и потерпел неудачу, затем попытался END, снова не удалось, нет других доступных вариантов, поэтому здесь была последняя альтернатива производственной стоимости, поэтому с точки зрения анализатора ожидалось END , но вскоре он нашел, следующий вход был blah2 с 4-й линии.

  • Как это исправить?

Постарайтесь быть ближе к реализации, грамматика в вашем случае должно быть:

examples ::= {divider example} 
divider ::= Integer")" 
example ::= {literal ["END"]} 

, и я думаю, что разбор «пример» в List[String] имеет больше смысла, во всяком случае, это до вас.

Проблема заключается в том, что ваш парсер example, это должен быть повторяемый литерал.

Так,

class ParsComb extends RegexParsers { 
    def examples: Parser[List[Example]] = rep(divider ~ example) ^^ { _ map { case d ~ e => Example(d, e) } } 
    def divider: Parser[Int] = "[0-9]+".r <~ ")" ^^ (_.toInt) 
    def example: Parser[List[String]] = rep("[\\w]*(?=[\\r\\n])".r <~ opt("END")) 
} 

регулярное выражение (?=[\\r\\n]) означает, что это положительный предпросмотр и будет соответствовать символы, которые следуют \r или \n.

результатом синтаксического анализа является:

[10.1] разобран: Список (пример (0, List (blah1, blah2, blah3)), Пример (1, Список (blah4, blah5)))

Если вы хотите, чтобы разобрать его в строку (вместо из List[String]), просто добавить функцию преобразования, например: ^^ {_ mkString "\n"}

+0

Спасибо, отличный ответ - напишите больше в StackOverflow! –

2

Ваш анализатор не может обрабатывать символ новой строки, ваш example анализатор устраняет следующий divider и ваш example регулярное выражение соответствует divider и «END» строку.

Попробуйте это:

object ParsComb extends RegexParsers { 
    def examples: Parser[List[Example]] = rep(divider~example) <~ """END\n?""".r ^^ {_ map {case d ~ e => Example(d,e)}} 
    def divider: Parser[Int] = "[0-9]+".r <~ ")\n" ^^ (_.toInt) 
    def example: Parser[String] = rep(str) ^^ {_.mkString} 
    def str: Parser[String] = """.*\n""".r ^? { case s if simpleLine(s) => s} 

    val div = """[0-9]+\)\n""".r 
    def simpleLine(s: String) = s match { 
    case div() => false 
    case "END\n" => false 
    case _ => true 
    } 

    def apply(s: String) = parseAll(examples, s) 
} 

Результат:

scala> ParsComb(input) 
res3: ParsComb.ParseResult[List[Example]] = 
[10.1] parsed: List(Example(0,blah1 
blah2 
blah3 
), Example(1,blah4 
blah5 
)) 
+0

0 0 Спасибо, так это поможет мне понять, что происходит! –

1

Я думаю, что проблема может быть с г регулярного выражения не делать многострочных «*.»..

Точно. Используйте модификатор dotall (странно называемый «s»):

def example: Parser[String]  = "(?s).*".r <~ (divider | "END") 
Смежные вопросы