2013-07-25 1 views
1

Je face à un comportement peu clair de parseurs parsec, donc je veux parsre cordes en mêmeanalyseur Parsec a échoué sur many1 et manyTill Combinators

> <CdId> 
1 

> <Mol Weight> 
270.2369 

> <Formula> 
C15H10O5 

> <LOG_ER_RBA> 
-0.36 

> <ACTIVITY> 
1 

J'ai écrit un analyseur

parseProperties = do  
     skipMany1 newline 
     char '>' >> spaces >> char '<' 
     propName <- many1 (noneOf ">") 
     char '>' 
     newline 
     propValue <- many1 (noneOf "\n") 
     return (propName,propValue) 

Cet analyseur très bien analyser un élément, et est également capable d'analyser plusieurs:

parseTest (count 5 parseProperties) "\n> <CdId>\n1\n\n> <Mol Weight>\n270.2369\n\n> <Formula>\nC15H10O5\n\n> <LOG_ER_RBA>\n-0.36\n\n> <ACTIVITY>\n1\n\n" 

résultats

[("CdId","1"),("Mol Weight","270.2369"),("Formula","C15H10O5"),("LOG_ER_RBA","-0.36"),("ACTIVITY","1")] 

Néanmoins j'ai trouvé aucun moyen pour analyser les nombres aléatoires de propriétés. Si je tente

parseTest (many1 parseProperties) "\n> <CdId>\n1\n\n> <Mol Weight>\n270.2369\n\n> <Formula>\nC15H10O5\n\n> <LOG_ER_RBA>\n-0.36\n\n> <ACTIVITY>\n1\n\n" 

ou

parseTest (manyTill parseProperties (try eof)) "\n> <CdId>\n1\n\n> <Mol Weight>\n270.2369\n\n> <Formula>\nC15H10O5\n\n> <LOG_ER_RBA>\n-0.36\n\n> <ACTIVITY>\n1\n\n" 
analyseur

n'a

parse error at (line 17, column 1): 
unexpected end of input 
expecting new-line or ">" 

Mais, si j'utilise l'analyseur AnyChar, il est pas échoué.

parseTest (manyTill anyChar (try eof)) "\n> <CdId>\n1\n\n> <Mol Weight>\n270.2369\n\n> <Formula>\nC15H10O5\n\n> <LOG_ER_RBA>\n-0.36\n\n> <ACTIVITY>\n1\n\n" 

"\n> <CdId>\n1\n\n> <Mol Weight>\n270.2369\n\n> <Formula>\nC15H10O5\n\n> <LOG_ER_RBA>\n-0.36\n\n> <ACTIVITY>\n1\n\n" 
+0

Puis-je vous informer que 'many1 (noneOf"> ")' est une mauvaise pratique. Utilisez «noneOf» avec parcimonie - il est préférable de décider ce qui est autorisé au lieu de ce qui ne l'est pas. Vous avez dit qu'un 'propertyName' est quelque chose qui n'est pas un'> '. Cela permet une propriété appelée '%^$ \ t 5 &/\ n \ n AndrewC

Répondre

2

L'analyseur parseProperties est exécuté plusieurs fois dans votre exemple jusqu'à ce que eof se rencontre. Le problème est que parseProperties ne consomme pas l'espace de fin dans votre exemple, donc après l'analyse de la dernière balise, la chaîne restante est "\n\n", ce qui ne déclenchera pas votre condition de terminaison , car ce n'est pas la fin de l'entrée. Cela provoque le parseProperties être tenté à nouveau, qui consomme les espaces, mais échoue lors de la tentative de manger un '>'.

Essayez de modifier votre parseTest à ce qui suit

test = "\n> <CdId>\n1\n\n> <Mol Weight>\n270.2369\n\n> <Formula>\nC15H10O5\n\n> <LOG_ER_RBA>\n-0.36\n\n> <ACTIVITY>\n1\n\n" 

parseTest (manyTill parseProperties $ try (skipMany newline >> eof)) test 

Ce TRYS dépouillant les espaces blancs précédent avant de vérifier si elle est à une extrémité d'entrée.

+0

Merci, ça a résolu le problème –

1

Dans le cas où la quantité de "\ n" est aléatoire, j'utiliser cette version (plutôt que d'ajouter un analyseur supplémentaire):

parseProperties :: Parser (String,String) 
parseProperties = do 
    skipMany newline -- optional newline(s) 
    char '>' >> spaces >> char '<' 
    propName <- many1 (noneOf ">") 
    char '>' 
    newline 
    propValue <- many1 (noneOf "\n") 
    skipMany newline -- optional newline(s) 
    return (propName,propValue) 

J'ai essayé cette version:

parseTest (many1 parseProperties) "\n> <CdId>\n1\n\n> <Mol Weight>\n270.2369\n\n><Formula>\nC15H10O5\n\n> <LOG_ER_RBA>\n-0.36\n\n> <ACTIVITY>\n1\n\n" 

Et got:

[("CdId","1"),("Mol Weight","270.2369"),("Formula","C15H10O5"),("LOG_ER_RBA","-0.36"),  ("ACTIVITY","1")] 
Questions connexes