2014-06-08 10 views
5

I Eingabezeichenfolgen wie diese analysieren will: "this is \"test \" message \"sample\" text"Parser für Zitiert Zeichenfolge mit Parsec

Nun, ich einen Parser zum Parsen von individuellem Text ohne Anführungszeichen geschrieben:

parseString :: Parser String 
parseString = do 
    char '"' 
    x <- (many $ noneOf "\"") 
    char '"' 
    return x 

parst Diese einfache Zeichenkette wie diese : "test message"

Dann schrieb ich einen Parser für Strings in Anführungszeichen:

quotedString :: Parser String 
quotedString = do 
    initial <- string "\\\"" 
    x <- many $ noneOf "\\\"" 
    end <- string "\\\"" 
    return $ initial ++ x ++ end 

Dieser Parser für Strings wie diesen: \"test message\"

Gibt es eine Möglichkeit, dass ich die beiden Parser kombinieren kann, damit ich mein gewünschtes Ziel erreiche? Was genau ist der idiotische Weg, um dieses Problem anzugehen?

+0

Warum möchten Sie die ersten und letzten Anführungszeichen entfernen, aber die escaping Backslashes intakt lassen? Ich würde denken, dass Sie die Eingabe "" \ "\" \ "c \" "entweder als" \ "ab \" c \ "" "(parsing strict für die Validierung) oder als" "ab \" c ", aber es scheint, du willst" "ab \" c ", was nicht so offensichtlich nützlich scheint. – dfeuer

+0

@dfeuer Kein besonderer Grund, spielte nur mit Parsec herum. – Sibi

Antwort

17

Dies ist, was ich tun würde:

escape :: Parser String 
escape = do 
    d <- char '\\' 
    c <- oneOf "\\\"0nrvtbf" -- all the characters which can be escaped 
    return [d, c] 

nonEscape :: Parser Char 
nonEscape = noneOf "\\\"\0\n\r\v\t\b\f" 

character :: Parser String 
character = fmap return nonEscape <|> escape 

parseString :: Parser String 
parseString = do 
    char '"' 
    strings <- many character 
    char '"' 
    return $ concat strings 

Alles was Sie jetzt tun müssen, ist es zu nennen:

parse parseString "test" "\"this is \\\"test \\\" message \\\"sample\\\" text\"" 

Parser Kombinatoren sind ein bisschen schwierig, zunächst zu verstehen, aber sobald man sich Der Fall ist einfacher als das Schreiben von BNF-Grammatiken.

+1

Sollte 'nonEscape' nicht nur' noneOf "\\\" "' sein, damit Sonderzeichen wörtlich erscheinen können, während die Verarbeitung erheblich beschleunigt wird? – dfeuer

+0

@dfeuer Ich denke, er hat nur einige zusätzliche Zeichen hinzugefügt, um es zu demonstrieren, falls ich sie hinzufügen wollte. :) – Sibi

+0

@Sibi, mein Punkt war, dass es besser sein könnte, die Extra-Escapes in die Definition von 'escape' * zu setzen, ohne sie von' nonEscape' auszuschließen. Die einzigen Dinge, die offensichtlich von 'nonEscape' * ausgeschlossen werden müssen, sind' ''' '' '' '' '. – dfeuer

2
quotedString = do 
    char '"' 
    x <- many (noneOf "\"" <|> (char '\\' >> char '\"')) 
    char '"' 
    return x 

Ich glaube, das sollte funktionieren.

+0

Dies wird \ im Ergebnis enthalten. '" \ "" wird zu "\" 'not' "' geparkt. –

+0

@Banthar, das scheint die Absicht des OP zu sein. Der Code scheint jedoch nicht so flexibel zu sein wie der von Aadit M. Shahs Antwort und es sieht so aus, als ob es schwer wäre, es zu erweitern, um Backslashes zu vermeiden – dfeuer

0

ziehe ich die folgende, weil es leichter zu lesen ist:

quotedString :: Parser String 
quotedString = do 
    a <- string "\"" 
    b <- concat <$> many quotedChar 
    c <- string "\"" 
    -- return (a ++ b ++ c) -- if you want to preserve the quotes 
    return b 
    where quotedChar = try (string "\\\\") 
        <|> try (string "\\\"") 
        <|> ((noneOf "\"\n") >>= \x -> return [x]) 

Aadit-Lösung schneller sein kann, weil es nicht try nicht verwendet, aber es ist wahrscheinlich schwieriger zu lesen.

Beachten Sie, dass es sich von Aadits Lösung unterscheidet. Meine Lösung ignoriert entgangene Dinge in der Zeichenfolge und kümmert sich nur um \" und \\.

Nehmen wir zum Beispiel an, Sie haben ein Tab-Zeichen in der Zeichenfolge. Meine Lösung analysiert erfolgreich "\"\t\"" zu Right "\t". Aadits Lösungen sagen unexpected "\t"expecting "\\" or "\"".

Beachten Sie auch, dass die Lösung von Aadit nur "gültige" Escapezeichen akzeptiert. Zum Beispiel weist es "\"\\a\"" zurück. \a ist keine gültige Escape-Sequenz (gut gemäß , es stellt die Systemglocke dar und ist gültig). Meine Lösung gibt einfach Right "\\a" zurück.

So haben wir zwei verschiedene Anwendungsfälle.

  • Meine Lösung: Strings in Anführungszeichen Parse mit möglicherweise Anführungszeichen entkommen und flüchtete entkommt

  • Aadit Lösung: quoted Strings mit gültigen Escape-Sequenzen Parse wo gültig entkommt "\\\"\0\n\r\v\t\b\f"

0

ich wollte bedeutet Analysieren Sie in Anführungszeichen gesetzte Strings und entfernen Sie alle Backslashes, die während des Parsing-Schritts für das Entweichen verwendet wurden. In meiner einfachen Sprache waren die einzigen Escape-Zeichen doppelte Anführungszeichen und umgekehrte Schrägstriche. Hier ist meine Lösung:

quotedString = do 
    string <- between (char '"') (char '"') (many quotedStringChar) 
    return string 
    where 
    quotedStringChar = escapedChar <|> normalChar 
    escapedChar = (char '\\') *> (oneOf ['\\', '"']) 
    normalChar = noneOf "\"" 
0

Falls jemand für eine aus der Box Lösung suchen, bietet this answer in code-review genau das. Hier ist ein vollständiges Beispiel mit den richtigen Importen:

import   Text.Parsec 
import   Text.Parsec.Language 
import   Text.Parsec.Token 

lexer :: GenTokenParser String u Identity 
lexer = makeTokenParser haskellDef 

strParser :: Parser String 
strParser = stringLiteral lexer 

parseString :: String -> Either ParseError String 
parseString = parse strParser "" 
Verwandte Themen