如何读取带有“?”的CSV行?
一行简单的CSV(逗号分隔值)数据可以用字符串的分割功能来处理。但是,有些行可能会包含"
,例如:
"good,morning", 100, 300, "1998,5,3"
所以直接用字符串分割的方法就不能解决这个问题。
我的解决办法是先用,
来分割这一行,然后再把字符串中开头或结尾的"
合并起来。
对于这个问题,最佳的做法是什么呢?
我想知道有没有Python或F#的代码示例可以参考。
编辑:我更关心的是具体的实现细节,而不是使用某个库。
4 个回答
2
通用的实现细节大概是这样的(未经测试)
def csvline2fields(line):
fields = []
quote = None
while line.strip():
line = line.strip()
if line[0] in ("'", '"'):
# Find the next quote:
end = line.find(line[0])
fields.append(line[1:end])
# Find the beginning of the next field
next = line.find(SEPARATOR)
if next == -1:
break
line = line[next+1:]
continue
# find the next separator:
next = line.find(SEPARATOR)
fields.append(line[0:next])
line = line[next+1:]
3
来自 Python的CSV模块:
读取一个普通的CSV文件:
import csv
reader = csv.reader(open("some.csv", "rb"))
for row in reader:
print row
读取一个格式不同的文件:
import csv
reader = csv.reader(open("passwd", "rb"), delimiter=':', quoting=csv.QUOTE_NONE)
for row in reader:
print row
在LinuxJournal.com上有一些很好的使用示例。
如果你对细节感兴趣,可以看看“在字符串不符合CSV格式时,按逗号分割字符串并尊重引号”,里面有一些与这个问题相关的很棒的正则表达式,或者直接阅读CSV模块的源代码。
11
在Python中,有一个叫做csv的模块,可以处理这个问题。
编辑: 这个任务属于“构建词法分析器”的范畴。通常做这种事情的方法是构建一个状态机(或者使用一个词法分析器库/框架来帮你完成)。
这个任务的状态机可能只需要两个状态:
- 第一个状态是初始状态,在这个状态下,它会把每个字符(除了逗号和换行符)都当作字段的一部分(例外:开头和结尾的空格),逗号作为字段的分隔符,换行符作为记录的分隔符。当它遇到一个开引号时,就会进入下一个状态。
- 第二个状态是读取带引号的字段状态,在这个状态下,所有字符(包括逗号和换行符)都被视为字段的一部分,除了引号。一个引号后面没有跟着另一个引号就意味着读取带引号的字段结束(回到初始状态),而一个引号后面跟着另一个引号则被视为一个单独的引号(转义引号)。
顺便说一下,你的拼接解决方案在处理"Field1","Field2"
或"Field1"",""Field2"
时会出问题。