【问题标题】:Is there a more "Pythonic" way to combine CSV elements?是否有更“Pythonic”的方式来组合 CSV 元素?
【发布时间】:2011-09-26 10:29:03
【问题描述】:

基本上我使用 python cron 从网络读取数据并将其以以下形式放置在 CSV 列表中:

.....
###1309482902.37
entry1,36,257.21,16.15,16.168
entry2,4,103.97,16.36,16.499
entry3,2,114.83,16.1,16.3
entry4,130.69,15.6737,16.7498
entry5,5.20,14.4,17
$$$
###1309482902.37
entry1,36,257.21,16.15,16.168
entry2,4,103.97,16.36,16.499
entry3,2,114.83,16.1,16.3
entry4,130.69,15.6737,16.7498
entry5,5.20,14.4,17
$$$

.....

我的代码基本上是进行正则表达式搜索并遍历 ### 和 $$$ 之间的所有匹配项,然后逐行遍历每个匹配项,取每一行并用逗号分隔。如您所见,有些条目有 4 个逗号,有些有 5 个。那是因为我很笨,没有意识到网络源将逗号放在它的 4 位数字中。浏览器

entry1,36,257.21,16.15,16.168

应该是真的

entry1,36257.21,16.15,16.168

我已经收集了很多数据,不想重写,所以想了一个繁琐的解决方法。有没有更 Pythonic 的方式来做到这一点?

===

contents = ifp.read()

#Pull all entries from the market data
for entry in re.finditer("###(.*\n)*?\$\$\$",contents):

    dataSet = contents[entry.start():entry.end()]
    dataSet = dataSet.split('\n');

    timeStamp = dataSet[0][3:]
    print timeStamp

    for i in xrange(1,8):
        splits = dataSet[i].split(',')
        if(len(splits) == 5):
            remove = splits[1]
            splits[2] = splits[1] + splits[2]
            splits.remove(splits[1])
        print splits
        ## DO SOME USEFUL WORK WITH THE DATA ##

===

【问题讨论】:

  • Pythonic 的方式是首先使用csv运行

标签: python list csv


【解决方案1】:

编写此代码块的更 Pythonic 方式

for i in xrange(1,8):
    splits = dataSet[i].split(',')
    if(len(splits) == 5):
        remove = splits[1]
        splits[2] = splits[1] + splits[2]
        splits.remove(splits[1])
    print splits

for row in dataSet:
    name, data = row.split(',', 1)
    print [name] + data.rsplit(',', 2)

【讨论】:

    【解决方案2】:

    其他人建议您使用csv 来解析文件,这是个好建议。但它并没有直接解决另一个问题——即,您正在处理一个由数据部分组成的文件。通过将文件转换为单个字符串,然后使用正则表达式来解析该大字符串,您将丢弃文件的一个关键杠杆点。另一种策略是编写一个可以解析文件的方法,一次生成一个部分。

    def read_next_section(f):
        for line in f:
            line = line.strip()
            if line.startswith('#'):
                # Start of a new section.
                ts = line[3:]
                data = []
            elif line.startswith('$'):
                # End of a section.
                yield ts, data
            else:
                # Probably a good idea to use csv, as others recommend.
                # Also, write a method to deal with extra-comma problem.
                fields = line.split(',')
                data.append(fields)
    
    with open(sys.argv[1]) as input_file:
        for time_stamp, section in read_next_section(input_file):
            # Do stuff.
    

    【讨论】:

    • 非常漂亮和干净的代码。你能解释一下你所说的杠杆是什么意思吗?你的意思是更少的内存使用,因为我没有一次读取整个文件,或者由于更小的搜索空间而更有效的搜索
    • @Chris Anderson 我的观点与内存或速度无关。而是关于解析策略。解析通常会导致丑陋的代码。为了避免这种丑陋,您需要利用数据提供的关键杠杆作用。这些杠杆点允许您区分文件的有意义的部分。在您的情况下,有意义的单位是线条和部分。通过将文件拼凑成一个字符串,您可以消除这些区别,因此必须跳过各种障碍才能重新获得它们(例如,将文本拆分为换行符)。
    【解决方案3】:

    我会使用 Python 的 csv module 读取 CSV 文件,修复遇到的损坏行,然后使用 csv.writer 将 CSV 写回。像这样(假设你的原始文件,逗号在错误的地方,是ugly.csv,新的,清理后的输出文件将是pretty.csv):

    import csv
    
    inputCsv = csv.reader(open("ugly.csv", "rb"))
    outputCsv = csv.writer(open("pretty.csv", "wb"))
    
    for row in inputCsv:
      if len(row) >= 5:
        row[1] = row[1] + row[2] #note that csv entries are strings, so this is string concatenation, not addition
        del row[2]
      outputCsv.writerow(row)
    

    简洁明了,而且,由于您使用的是正确的 CSV 解析器和写入器,因此您不必担心引入任何新的奇怪的极端情况(如果您在第一个脚本中使用过它,解析网络结果,您输入数据中的逗号会被转义)。

    【讨论】:

      【解决方案4】:

      csv 模块通常用于处理所有格式的 CSV 文件。

      但是,在这里,逗号出现了这种丑陋的情况,因此丑陋的 hack 是合适的。我没有看到一个干净的解决方案,所以我认为可以使用任何可行的方法。

      顺便说一句,这行似乎是多余的:

      remove = splits[1]
      

      【讨论】:

      • 你没有理由不在这里使用csv(而不是像正则表达式那样丑陋的hack)。读入 CSV 文件,在遇到损坏的行时修复它们,然后使用 csv.writer 将 CSV 文件写回。
      • 好吧,我使用正则表达式,因为它不是真正的 CSV。该文件的格式为### ... $$$ 每个数据集都受此格式约束,每个数据集都包含多行 CSV 数据。拆分应该就足够了,如果它不是真正的 CSV,那么 REGEX 有什么问题?
      猜你喜欢
      • 1970-01-01
      • 2021-10-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-15
      • 1970-01-01
      • 2023-01-09
      • 2011-01-28
      相关资源
      最近更新 更多