2011-06-15 61 views
6

我有数据,看起来像:如何使用Python的csv模块拆分双管道分隔数据

"1234"||"abcd"||"a1s1" 

我试图读取和使用Python的CSV读者和作家写的。 由于csv模块的分隔符仅限于单个字符,有没有什么办法可以干净地检索数据?我不能删除空列,因为它是一个庞大的数据集,需要以时间限制的方式进行处理。任何想法都会有所帮助。

+1

你说你不能就让它去,然后取出后的空列可选的报价。当你尝试时,它是什么因素太慢? – 2011-06-15 02:48:09

+0

问题应该指出我们是否可以从示例数据中推广。我的答案在下面假设'是'。 – 2012-07-01 00:30:06

回答

12

The docs和实验证明,只有单字符分隔符是允许的。

由于cvs.reader接受支持迭代器协议的任何对象,则可以使用发电机的语法与| -s取代|| -s,再喂该发电机向读者:

def read_this_funky_csv(source): 
    # be sure to pass a source object that supports 
    # iteration (e.g. a file object, or a list of csv text lines) 
    return csv.reader((line.replace('||', '|') for line in source), delimiter='|') 

此代码是非常有效的因为它在时间上的一个CSV线运行,提供您的CSV源线的产量不超过可用的RAM :)

+7

推测使用双管分隔符的原因是因为在给定值中可能存在单个管道。 – Arafangion 2011-06-15 04:03:36

+0

@Arafangion:是的。也许需要更复杂的生成器表达式来缓解这个缺陷。 – 2011-06-15 04:38:09

+0

@Arafangion只需用另一个分隔符(,; $%} ^ø或其他)在一个值中不会出现的双管分隔符替换即可。 – 2012-08-17 08:43:03

1

不幸的是,分隔符是由下一个字符来表示这意味着它是不可能有它除Py之外的其他任何字符马拉松。好消息是,它是可以忽略它们是空值:

reader = csv.reader(['"1234"||"abcd"||"a1s1"'], delimiter='|') 
#iterate through the reader. 
for x in reader: 
    #you have to use a numeric range here to ensure that you eliminate the 
    #right things. 
    for i in range(len(x)): 
     #Odd indexes will be discarded. 
     if i%2 == 0: x[i] #x[i] where i%2 == 0 represents the values you want. 

还有其他的方法来完成这个(函数可以写为一个),但是这给你所需要的逻辑。

+0

你将如何处理:'1234 || ab | cd || a1s1'? – Arafangion 2011-06-15 04:53:51

+0

@Arafangion最初的例子不仅仅是管道划定的,它是管道和双引号划定的。这意味着csv.reader将忽略行中心的管道。 – cwallenpoole 2011-06-15 05:06:53

2
>>> import csv 
>>> reader = csv.reader(['"1234"||"abcd"||"a1s1"'], delimiter='|') 
>>> for row in reader: 
...  assert not ''.join(row[1::2]) 
...  row = row[0::2] 
...  print row 
... 
['1234', 'abcd', 'a1s1'] 
>>> 
1

如果你的数据从字面上看起来像例子(字段不会包含“||”,总是引用),你能容忍引号,还是愿意以后切片他们,只是使用.split如果分隔符领域内发现只需要

>>> '"1234"||"abcd"||"a1s1"'.split('||') 
['"1234"', '"abcd"', '"a1s1"'] 
>>> list(s[1:-1] for s in '"1234"||"abcd"||"a1s1"'.split('||')) 
['1234', 'abcd', 'a1s1'] 

CSV或删除周围领域