【问题标题】:Processing CSV file without double quotes处理不带双引号的 CSV 文件
【发布时间】:2017-06-13 12:30:55
【问题描述】:

换句话说,我正在寻找一种方法来忽略其中一个字段中的“,”。

该字段应被视为一个字段,即使它包含逗号。

例子:

Round,Winner,place,prize
1,xyz,1,$4,500

如果我使用 dict reader $4,500 阅读此内容,则将其打印为 $4,因为 500 被认为是另一个字段。,这是有道理的,因为我正在阅读以逗号分隔的文件,所以我真的不能抱怨,但想办法解决。

reader = csv.reader(f, delimiter=',', quotechar='"')

我的来源没有用双引号括起来,所以我不能通过包含引号字符串来忽略。

还有其他方法可以处理这种情况吗?可能类似于定义这些美元字段并使其忽略该字段的逗号?或者尝试在该字段周围插入引号?

如果不是 Python,可以使用 shell 脚本或 Perl 吗?

【问题讨论】:

  • 您的输入数据已损坏,您只能获得诸如“忽略美元符号后的第一个逗号”之类的创可贴解决方案 - 是否足够?
  • 幸运的是 prize 列是最后一个,否则这将更加令人头疼(使用标题来跟踪列的数量,m,取列直到美元符号,从右边取列,直到你得到它们中的m-1,然后将中间的剩余内容打到形成prize 字段...blech)
  • @Benjamin W - 是的,在这一点上,我必须假设我会得到一个损坏的数据,如果不是总是但有时可能会。所以绷带现在是首选。
  • @JackManey ...让我试一试。谢谢

标签: python perl shell csv delimiter


【解决方案1】:

也许预处理数据以将所有钱都用引号括起来,然后正常处理

$line =~ s/( \$\d+ (?:,\d{3})* (?:\.\d{2})? )/"$1"/gx;

该模式匹配$ 之后的数字,可选地后跟,nnn 的任意倍数和/或一个.nn。它还包装了$4.22$100,我认为这有利于一致性。如果需要,限制匹配的内容,例如 (\$\d{1,3},\d{3})。使用分数美分删除{2}。这并未涵盖所有可能的边缘/破损情况。

/g 修饰符使其替换行中的所有内容,/x 允许空格以方便阅读。

你可以做一个单行

perl -pe 's/(\$\d+(?:,\d{3})*(?:\.\d{2})?)/"$1"/g' input.csv  > changed.csv

添加-i 开关以覆盖输入(“就地”),或添加-i.bak 以保留备份。


如果您预计需要进一步调整,或者为了更好地记录这一点,请将其放入脚本中

use warnings;
use strict;

my $file = '...';
my $fout = '...';

open my $fh,     '<', $file or die "Can't open $file: $!";
open my $fh_out, '>', $fout or die "Can't open $fout for writing: $!";

while (my $line = <$fh>) {
    $line =~ s/( \$\d+ (?:,\d{3})* (?:\.\d{2})? )/"$1"/gx;
    print fh_out $line;
}

close $fh;
close $fh_out;

【讨论】:

  • zdim:您提到了限制:由于我们对其他字段中出现的值一无所知,因此尾随的 $,紧跟逗号也会匹配!所以 /(\$\d[\d,]+)/ 的最小限制可能,或者考虑到货币重新格式化的情况: /(\$\d{1,3}(?:,\d{3} )+)/ ?
  • @SREagle,我应用了修复程序。
  • ikegami: 'bling$$$,100,' =~ /(\$[\d,]*\d)/ 怎么样?那还不匹配吗?
  • 这是一种启发式方法,因此人们总能想出一个案例,在不应该的情况下将某些东西解释为价格。关键是找到一种适用于实际遇到的数据的解决方案。但是,是的,\$\d+(?:,\d{3})*\$[\d,]*\d 更好,因为它的限制性更强,而且它执行的回溯更少。
  • @jb04 除非有固定的地址格式,否则几乎不可能准确解析。最终,您尝试使用技术解决方案来解决非技术问题(您的数据提供商给您提供了损坏的数据),而这绝不是成功的秘诀。
【解决方案2】:

如果额外的, 在存在时始终是最后一个字段的一部分,则可以使用 Bash 读取循环:

#!/bin/bash

while IFS=, read -r f1 f2 f3 f4; do
   # f4 => has everything after f3, including extra commas as in $4,500
   # do your processing
   printf "f1=[$f1] f2=[$f2] f3=$[f3] f4=[$f4]\n"
done < input.txt

输入:

1,xyz,1,$4,500
2,abc,3,$400

输出:

f1=[1] f2=[xyz] f3=1 f4=[$4,500]
f1=[2] f2=[abc] f3=3 f4=[$400]

【讨论】:

  • 问题是我可能正在阅读许多 csv 文件,并且每个文件都有不同的布局或没有字段。所以很难说它是否总是在最后,以及我在文件中预期有多少字段。我必须编写一个动态的方法来定义没有字段,而且我不确定在处理大型数据集时是否存在任何性能瓶颈
猜你喜欢
  • 1970-01-01
  • 2014-04-22
  • 1970-01-01
  • 1970-01-01
  • 2016-03-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-08-06
相关资源
最近更新 更多