J'ai essayé d'utiliser pyparsing
pour analyser un fichier CSV avec:Comment analyser un fichier CSV par des virgules entre parenthèses et les valeurs manquantes
- entre parenthèses Commas (ou entre parenthèses, etc.): « a (1,2) , b "devrait retourner la liste [" a (1,2) "," b "]
- Valeurs manquantes:" a, b ,, c, "devrait retourner la liste ['a', 'b' , '', 'c', '']
J'ai travaillé une solution mais elle semble "sale". Principalement, le Optional
à l'intérieur d'un seul des atomiques possibles. Je pense que l'option devrait être indépendante des atomes. C'est-à-dire, je pense qu'il devrait être mis ailleurs, par exemple dans les arguments facultatifs delimitedList
, mais dans mon essai et erreur c'était le seul endroit qui a fonctionné et fait sens. Il pourrait être dans l'un des atomiques possibles, donc j'ai choisi le premier.
En outre, je ne comprends pas complètement ce que fait originalTextFor
mais si je l'enlève il cesse de fonctionner.
Exemple de travail:
import pyparsing as pp
# Function that parses a line of columns separated by commas and returns a list of the columns
def fromLineToRow(line):
sqbrackets_col = pp.Word(pp.printables, excludeChars="[],") | pp.nestedExpr(opener="[",closer="]") # matches "a[1,2]"
parens_col = pp.Word(pp.printables, excludeChars="(),") | pp.nestedExpr(opener="(",closer=")") # matches "a(1,2)"
# In the following line:
# * The "^" means "choose the longest option"
# * The "pp.Optional" can be in any of the expressions separated by "^". I put it only on the first. It's used for when there are missing values
atomic = pp.originalTextFor(pp.Optional(pp.OneOrMore(parens_col)))^pp.originalTextFor(pp.OneOrMore(sqbrackets_col))
grammar = pp.delimitedList(atomic)
row = grammar.parseString(line).asList()
return row
file_str = \
"""YEAR,a(2,3),b[3,4]
1960,2.8,3
1961,4,
1962,,1
1963,1.27,3"""
for line in file_str.splitlines():
row = fromLineToRow(line)
print(row)
Prints:
['YEAR', 'a(2,3)', 'b[3,4]']
['1960', '2.8', '3']
['1961', '4', '']
['1962', '', '1']
['1963', '1.27', '3']
Est-ce la bonne façon de le faire? Y a-t-il un moyen "plus propre" d'utiliser le Optional
à l'intérieur du premier atome?
Pour la conversion des valeurs numériques en temps parse, changez atomic' en: atomic = pp.pyparsing_common.number | pp.originalTextFor (... etc.' – PaulMcG