【发布时间】:2017-11-01 13:03:59
【问题描述】:
我尝试使用 pyparsing 解析 CSV:
- 括号(或方括号等)之间的逗号: "a(1,2),b" 应返回列表 ["a(1,2)","b"]
- 缺失值:“a,b,,c”应返回列表 ['a','b','','c','']
我找到了一个解决方案,但它看起来很“脏”。主要是,Optional 里面只有一个可能的原子。我认为可选应该独立于原子。也就是说,我觉得它应该放在其他地方,例如在 delimitedList 可选参数中,但在我的反复试验中,这是唯一有效且有意义的地方。它可以在任何可能的原子中,所以我选择了第一个。
另外,我不完全理解 originalTextFor 在做什么,但如果我删除它,它就会停止工作。
工作示例:
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)
打印:
['YEAR', 'a(2,3)', 'b[3,4]']
['1960', '2.8', '3']
['1961', '4', '']
['1962', '', '1']
['1963', '1.27', '3']
这是正确的方法吗?有没有一种“更干净”的方式在第一个原子中使用 Optional?
【问题讨论】: