Benutzerdefinierte Fehler für RegexParsers

Darf mir jemand helfen, das folgende Verhalten zu verstehen: parseAll (parseIf, "Wenn bla blablaa") sollte dazu führen, dass erwartet wird . Stattdessen bekomme ich immer string matching regex 'ist \ b' erwartet, aber 'b' gefunden . Ich denke, es hat etwas mit Whitespaces zu tun, weil "If bla is blablaa" (beachten Sie die Whitespaces am Anfang) dasselbe Verhalten ergibt. Ich habe es mit StandardTokenParsers versucht und alles hat gut funktioniert. Aber STP unterstützt Regex leider nicht. Follow-up-Frage: Wie müsste ich RegexParsers ändern, so dass es eine Folge von Strings statt einer Folge von Zeichen verwendet? Das würde die Fehlerberichterstattung viel einfacher machen.

lazy val parseIf = roleGiverIf ~ giverRole

lazy val roleGiverIf =
  kwIf ~> identifier | failure("""A rule must begin with if""")
lazy val giverRole =
  kwIs ~> identifier | failure("""is expected""")

lazy val keyword =
  kwIf | kwAnd | kwThen | kwOf | kwIs | kwFrom | kwTo

lazy val identifier =
  not(keyword) ~ roleEntityLiteral
// ...

def roleEntityLiteral: Parser[String] =
  """([^"\p{Cntrl}\\]|\\[\\/bfnrt]|\\u[a-fA-F0-9]{4})\S*""".r 
def kwIf: Parser[String] = "If\\b".r
def kwIs: Parser[String] = "is\\b".r

// ...

parseAll(parseIf, "If bla blablaa") match {
  case Success(parseIf, _) => println(parseIf)
  case Failure(msg, _) => println("Failure: " + msg)
  case Error(msg, _) => println("Error: " + msg)
1

1 Antworten

Dieses Problem ist sehr seltsam. Wenn Sie | aufrufen und beide Seiten fehlschlagen, wird die Seite ausgewählt, auf der der Fehler aufgetreten ist last , wobei die Links bevorzugt werden.

Wenn Sie versuchen, direkt mit giverRole zu analysieren, wird das erwartete Ergebnis erzielt. Wenn Sie jedoch vor dem Fehler eine erfolgreiche Übereinstimmung hinzufügen, wird das Ergebnis angezeigt, das Sie sehen.

Der Grund ist eher subtil - ich habe es nur herausgefunden, indem ich log -Anweisungen auf alle Parser gestreut habe. Um es zu verstehen, müssen Sie verstehen, wie RegexParser Spaces überspringen . Insbesondere werden Leerzeichen über accept übersprungen. Da failure nicht accept aufruft, werden Leerzeichen nicht übersprungen.

Während der Fehler von kwIs in b auftritt, tritt der Fehler failure nach dem Überspringen des Speicherplatzes im Leerzeichen nach Wenn . Hier:

If bla blablaa
   ^ kwIs fails here
  ^ failure fails here

Daher wird die Fehlermeldung in kwIs Vorrang vor der Regel, die ich erwähnte.

Sie können dieses Problem umgehen, indem Sie den Parser dazu bringen, die Leerzeichen zu überspringen, ohne etwas zu finden. Es ist wichtig, dass dieses Muster immer übereinstimmt, oder Sie erhalten eine noch verwirrendere Fehlermeldung. Hier ist ein Vorschlag, der meiner Meinung nach funktioniert:

"\\b|$".r ~ failure("is expected")

Eine andere Lösung besteht darin, acceptIf oder acceptMatch zu verwenden, anstatt die implizite regex accept zu verwenden. In diesem Fall können Sie eine benutzerdefinierte Fehlermeldung bereitstellen.

0
hinzugefügt
@awertos Ich habe endlich herausgefunden, was das Problem war. Die erste Lösung war passender, als ich dachte - ich habe sie einfach geändert, um den Fehler an der richtigen Stelle erscheinen zu lassen, indem ich keine Leerzeichen verwendete.
hinzugefügt der Autor Daniel C. Sobral, Quelle
Ich habe einen Parser mit Regex und lexikalischen Fähigkeiten geschrieben und benutze acceptIf, wie Sie vorschlagen. Aber es ist immer noch seltsam, dass das obige Beispiel nicht wie erwartet funktioniert. Danke für Ihre Hilfe
hinzugefügt der Autor awertos, Quelle