使用CSV模块解析CSV字符串

4

我从外部源接收到CSV格式的数据,不希望将数据写入文件,这会导致许多维护任务,我想避免这种情况。我通过字符串形式获取数据。

现在我想将数据解析为CSV格式。Python模块csv非常适合这种情况,因此我使用它。

然而,构建一个CSV解析器需要使用csv.reader(或dictreader),需要数据支持迭代器。列表或读取器已经可以实现此功能。然而,我的数据包含在引号字符串内的换行符(对于CSV格式来说完全没有问题),以及作为记录结束标识符/行终止符的换行符。

如果我这样构造:

csvreader = csv.reader(data.split('\n'))

如果我将换行符解释为记录结束标志,即使它们在引号包含的字符串内部,我已经破坏了有效的CSV格式。对我而言,解释换行符应该由CSV解析器完成,因为它知道包含CSV相关格式字符(如换行符)的引用字段。

我是否对csv软件包解析器的工作方式有误解?或者,在数据包含不表示记录结束的换行符的情况下,我应该如何使用CSV解析器解析CSV类型的字符串?

编辑1:将上下文添加到我的问题可能不明智,因为上下文似乎已经超过了我的实际问题。澄清一下,我的问题不是从内存中解析CSV。我已经找到了StringIO。当使用StringIO时,所有操作只是将整个字符串/文件用作第一条记录。

编辑2:也许样本数据会有所帮助。我的数据看起来像这样:

"value1";"value2";"value3
stillvalue3"
"value4";"value5";"value6"

所以在第一条记录的第三个输入中有一个换行符,应将其解释为第一条记录的第三个输入的一部分。

编辑3:我当前使用解析器的方式如下:

csvreader = csv.reader(StringIO(result), quotechar='"', delimiter=';', lineterminator='\n', escapechar='"')

由于规范规定,在字段内部的双引号(")应该被引号字符("")转义,因此数据可能看起来像这样:
"value1";"value2";"value3
stillvalue3
a ""quote"" inside the quote"
"value4";"value5";"value6"

看起来使用这些设置,StringIO输入始终会生成一个包含字符串中所有数据的记录。去掉

escapechar='"'

修复了这个问题,然而我无法支持在引号内部的转义双引号字符。所以我的问题性质改变了。如果有人有想法,我会保持开放,并且稍后会接受Martin Evans的答案。

请参考以下链接了解如何让CSV Reader读取内存文件:https://dev59.com/DHTYa4cB1Zd3GeqPx7Qt - balderman
最简单的方法是使用 StringIO(现在是 from io import StringIO),如此所示:https://dev59.com/jnbZa4cB1Zd3GeqPIq9G#18724978 - jonrsharpe
1
问题在于(除了escapechar之外),csv.reader仅正确读取您显示的唯一数据。因此,我们必须猜测问题可能是什么。您必须展示一些展示问题的数据,包括您得到的和想要的内容。 - Serge Ballesta
1个回答

5
你可以使用Python的StringIO()将数据字符串转换成流接口。
不要尝试使用data.split('\n')来分割行,因为这样无法正确地分割行,而csv.reader()可以正确地读取行,即使单元格包含换行符:
from io import StringIO
import csv

data = '''"value1";"value2";"value3
stillvalue3"
"value4";"value5";"value6"'''

csv_input = csv.reader(StringIO(data, newline=''), delimiter=';')
rows = list(csv_input)
print("Rows", rows)    

给你:

Rows [['value1', 'value2', 'value3\nstillvalue3'], ['value4', 'value5', 'value6']]

然后可以将其加载到Pandas中,或直接使用StringIO()

columns = ['col1', 'col2', 'col3']

df = pd.DataFrame(rows, columns=columns)

df = pd.read_csv(StringIO(data, newline=''), names=columns, sep=';')

print(df)

给定:

     col1    col2                 col3
0  value1  value2  value3\nstillvalue3
1  value4  value5               value6

你的第二个例子给出:

Rows [['value1', 'value2', 'value3\nstillvalue3\na "quote" inside the quote'], ['value4', 'value5', 'value6']]

     col1    col2                                             col3
0  value1  value2  value3\nstillvalue3\na "quote" inside the quote
1  value4  value5                                           value6

请看我的修改。谢谢你的例子,但我尝试上面描述的问题在你的例子中并没有反映出来。 - 0xCAFEBABE
我已经更新了它,使用了你的例子。主要的重点不是尝试自己分割行,而是依靠csv.reader()来正确解析它。 - Martin Evans
如上所述,StringIO确实可以工作,但我使用的参数不起作用。我会保持开放一段时间,也许有人有想法,稍后再接受你的答案。 - 0xCAFEBABE
尝试在StringIO()调用中添加newline=''参数,就像我的示例一样。你的第二个示例对我来说似乎解析得很好。 - Martin Evans
1
使用建议的 newline='' 替换我之前在 CSV 解析器中使用的方法,效果非常好。现在它已经完全正确地解析了,正如您已经看到的那样。感谢您的时间。 - 0xCAFEBABE

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接