2012-10-17 5 views
14

Sto scrivendo il mio primo programma con Parsec. Voglio analizzare i dump dello schema di MySQL e vorrei creare un buon modo per analizzare stringhe che rappresentano determinate parole chiave in modo non sensibile al maiuscolo/minuscolo. Ecco un codice che mostra l'approccio che sto usando per analizzare "CREATE" o "create". C'è un modo migliore per farlo? Una risposta che non ricorra a buildExpressionParser sarebbe la cosa migliore. Sto facendo piccoli passi qui.Qual è il modo più semplice per eseguire l'analisi senza distinzione tra maiuscole e minuscole con Text.Combinators.Parsec?

p_create_t :: GenParser Char st Statement 
    p_create_t = do 
     x <- (string "CREATE" <|> string "create") 
     xs <- manyTill anyChar (char ';') 
     return $ CreateTable (x ++ xs) [] -- refine later 
+5

Suppongo che 'map toLower' sull'input prima che anche l'esecuzione del parser non sia un'opzione? Inoltre, mi aspetterei che "case insensitive" corrisponda anche a "Create", "CrEaTe", "CREATe" o qualsiasi altra variazione, che il tuo esempio rifiuta. Quale vuoi? –

+0

Questo funziona. Grazie. Non ci avevo pensato! – dan

+1

@dan State attenti che se il vostro input contiene stringhe, saranno anch'esse in minuscolo. Ad esempio, se una delle tue colonne contiene valori di stringa predefiniti. –

risposta

17

È possibile creare il parser senza distinzione tra maiuscole e minuscole dai parser di caratteri.

-- Match the lowercase or uppercase form of 'c' 
caseInsensitiveChar c = char (toLower c) <|> char (toUpper c) 

-- Match the string 's', accepting either lowercase or uppercase form of each character 
caseInsensitiveString s = try (mapM caseInsensitiveChar s) <?> "\"" ++ s ++ "\"" 
8

ripetere quello che ho detto in un commento, come è stato a quanto pare utile:

La soluzione semplice martello è quello di mappare semplicemente toLower sull'intera di ingresso prima di eseguire il parser, quindi fare tutto il vostro corrispondenza delle parole chiave in minuscolo.

Questo presenta evidenti difficoltà se si analizza qualcosa che deve essere insensibile alle maiuscole e minuscole in alcuni punti e sensibile alla distinzione tra maiuscole e minuscole in altri, oppure se si desidera conservare la custodia per ragioni estetiche. Ad esempio, anche se i tag HTML non fanno distinzione tra maiuscole e minuscole, la conversione di un'intera pagina Web in minuscolo durante l'analisi potrebbe essere indesiderata. Anche durante la compilazione di un linguaggio di programmazione insensibile alle maiuscole e minuscole, la conversione degli identificatori potrebbe essere fastidiosa, poiché i messaggi di errore risultanti non corrisponderebbero a ciò che il programmatore ha scritto.

0

Invece di mappatura dell'intero ingresso con toLower, è consigliabile utilizzare caseString da Text.ParserCombinators.Parsec.Rfc2234 (dal pacchetto hsemail)

Text.ParsecCombinators.Parsec.Rfc2234

p_create_t :: GenParser Char st Statement 
p_create_t = do 
    x <- (caseString "create") 
    xs <- manyTill anyChar (char ';') 
    return $ CreateTable (x ++ xs) [] -- refine later 

Così ora x verrà qualunque caso variante è presente nell'input senza modificare il tuo input.

ps: so che questo è un antico domanda, ho solo pensato che vorrei aggiungere questo come a questa domanda si avvicinò mentre ero alla ricerca di un problema simile

+0

Questo non è da Text.ParsecCombinators.Parsec. È da Text.ParsecCombinators.Parsec.Rfc2234. Il tuo link è corretto, ma il tuo titolo è sbagliato. Si noti inoltre che fa parte del pacchetto hsemail, che qualcuno potrebbe non aver già installato. – Sean

2

No, Parsec non può farlo in modo pulito. string è implementato sopra primitivo tokens combinatore che è hardcoded per utilizzare test di uguaglianza (==). È un po 'più semplice analizzare il carattere insensibile alle maiuscole e minuscole, ma è probabile che tu voglia di più lo .

C'è comunque una forchetta moderna di Parsec, chiamato Megaparsec che ha soluzioni incorporate per tutto ciò che si può desiderare:

λ> parseTest (char' 'a') "b" 
parse error at line 1, column 1: 
unexpected 'b' 
expecting 'A' or 'a' 
λ> parseTest (string' "foo") "Foo" 
"Foo" 
λ> parseTest (string' "foo") "FOO" 
"FOO" 
λ> parseTest (string' "foo") "fo!" 
parse error at line 1, column 1: 
unexpected "fo!" 
expecting "foo" 

Nota l'ultimo messaggio di errore, è meglio di quello che si può ottenere l'analisi caratteri uno per uno (particolarmente utile nel tuo caso particolare). string' è implementato proprio come Parsec string ma utilizza il confronto senza distinzione tra maiuscole e minuscole per confrontare i caratteri. Ci sono anche oneOf' e noneOf' che può essere utile in alcuni casi.


Disclosure: io sono uno degli Megaparsec autori.

+0

Davvero sorprendente che 'token' non consenta che una funzione di confronto venga passata ad essa per eseguire il confronto nel Parsec originale. – MicroVirus

Problemi correlati