2013-05-14 15 views
5

Als eine Folge zu: How do I test for exactly 2 characters with fparsec?Parser-IDs und freier Text im Format. Kann das mit FParsec gemacht werden?

Ich muss eine Zeichenfolge analysieren, die aus Paaren von Bezeichnern gefolgt von Freiform Text besteht. Ich kann leicht einen Parser konstruieren, der die Bezeichner in der Form von Newline gefolgt von genau zwei Großbuchstaben gefolgt von einem Leerzeichen findet. Der Freiform-Text, der dem vorhergehenden Bezeichner zugeordnet ist, ist alles, was dem Bezeichner folgt, jedoch nicht den nächsten Bezeichner einschließt.

So zum Beispiel:

AB Now is the 
time for all good 
men. 
CD Four score and seven years ago EF our. 

enthält zwei Kennungen AB und CD und zwei Stücke von Freitext

Now is the \ntime for all good men.
Four score and seven years ago EF our.

Mein Problem ist, ich weiß nicht, wie zu konstruieren Ein Parser, der dem Freiform-Text entspricht, aber nicht mit den Bezeichnern übereinstimmt. Ist das ein Fall, in dem ich Backtracking machen muss?

Kann dies getan werden und wenn ja wie?

Antwort

3

Ich denke, notFollowedBy ist was du suchst. Dies sollte den Trick tun:

// adapted from the other question 
let identifier = skipNewline >>. manyMinMaxSatisfy 2 2 CharParsers.isUpper 

let freeform = manyChars (notFollowedBy identifier >>. anyChar) 
4

Tarmil veröffentlichte die einfache Lösung.

Hier ist eine andere Variante, die nicht eine neue Zeile am Anfang und die am Ende der Leitungen überprüft nur für eine folgende Kennung benötigt:

let id = manyMinMaxSatisfyL 2 2 isUpper "ID" .>> pchar ' ' 

let text = 
    stringsSepBy (restOfLine true) 
       ((notFollowedBy ((id >>%()) <|> skipNewline <|> eof)) >>% "\n") 

let parser = many (id .>>. text) 

Wenn Sie den zweiten Parser mit der optimieren wollte stringsSepBy combinator, können Sie es mit der folgenden Version ersetzen:

let notFollowedByIdOrEmptyLineOrEof : Parser<string,_> = 
    fun stream -> 
     let cs = stream.Peek2() 
     let c0, c1 = cs.Char0, cs.Char1 
     if c0 = '\r' || c0 = '\n' || c0 = EOS 
      || (isUpper c0 && isUpper c1 && stream.Peek(2) = ' ') 
     then Reply(Error, NoErrorMessages) 
     else Reply("\n") 

let text2 = stringsSepBy (restOfLine true) 
         notFollowedByIdOrEmptyLineOrEof 
+0

Hallo, könnten Sie zu dieser Frage Stellung nehmen: https://bitbucket.org/fparsec/main/issue/29/portable-version-of- fparsec – Den