【问题标题】:Slight error when using awk to remove spaces from a CSV column使用 awk 从 CSV 列中删除空格时出现轻微错误
【发布时间】:2015-07-21 08:32:26
【问题描述】:

我在 bash 脚本中使用了以下 awk 命令来删除 CSV 第 26 列的空格;

awk 'BEGIN{FS=OFS="|"} {gsub(/ /,"",$26)}1' original.csv > final.csv

在 400 行中,我有大约 5 个随机行,即使我在 final.csv 上重新运行脚本,这也不起作用。任何人都可以帮助我解决这个问题吗?提前谢谢你。

编辑:这里分别是 original.csv 和 final.csv 第 26 列的示例;

2212026837                         2212026837
2256  41688  6                     2256416886
2076113566                         2076113566
2009  84517  7                     2009845177
2067950476                         2067950476
2057  90531  5                     2057  90531  5  
2085271676                         2085271676
2095183426                         2095183426
2347366235                         2347366235
2200160434                         2200160434
2229359595                         2229359595
2045373466                         2045373466
2053849895                         2053849895
2300  81552  3                     2300  81552  3

【问题讨论】:

  • 猜测行不是随机的,并且与其他行有所不同,只是猜测,因为您实际上没有提供任何有用的信息。
  • 猜想:这些行中的第 26 个字段是否包含制表符或其他非 0x20 空格,或者这些行中的先前字段之一是否包含带逗号的引号字符串?
  • 嗨。我已经用列示例更新了我的问题

标签: bash csv awk


【解决方案1】:

我看到了两种可能性。

  1. 最简单的方法是您有一些空格而不是空格。您可以通过在gsub 中使用更通用的正则表达式来解决此问题:而不是/ /,使用/[[:space:]]/

如果这能解决您的问题,那就太好了!你很幸运,继续前进。 :)

  1. 另一个可能的问题比较棘手。 CSV(或者,在这种情况下,管道-SV)格式并不像看起来那么简单,因为您可以在字段内使用引号分隔符。例如,这是一个用竖线分隔的文件中完全有效的 4 字段行:

    field 1|"field 2 contains some |pipe| characters"|field 3|field 4
    

    如果您文件中某行的前 4 个字段看起来像这样,那么您在 $26 上的 gsub 实际上会在 $24 上运行,而仅留下 $26。如果您有这样的数据,唯一真正的解决方案是使用带有实际 CSV 解析库的脚本语言。 Perl 有Text::CSV,但默认没有安装; Python 的 csv 模块是,所以你可以使用这样的程序:

    import csv, fileinput as fi, re;    
    for row in csv.reader(fi.input(), delimiter='|'):
      row[25] = re.sub(r'\s+', '', row[25]) # fields start at 0 instead of 1
      print '|'.join(row)
    

    将上述内容保存在colfixer.py 之类的文件中,然后使用python colfixer.py original.csv >final.csv 运行它。

    (如果你足够努力,你可以把它塞进一个-c 选项字符串中,然后在不创建脚本文件的情况下从命令行运行它,但是 Python 并不是真正为此而构建的,而且它很快就会变得丑陋。)

【讨论】:

  • 嗨。感谢你的回复。原来第一种可能性不是。因此,我尝试了 python 脚本,但它只记录了最后一行。我正在调查它,但如果你知道问题可能是什么,它肯定会为我节省很多时间:)。再次感谢您。
  • print '|'.join(row) 行是否与row[25] = 行在同一级别缩进?它们都应该缩进,以便它们在 for 循环内;如果printfor 匹配,则它只会打印最后一行。
  • 非常感谢。您的解决方案有效。但是,我的 CSV 在某些行上存在分隔符问题。我认为有一些引号引起了混乱。我会调查一下。再次,非常感谢你:)
【解决方案2】:

您可以使用string functionsplit,并遍历相应的数组以重新分配第26个字段:

awk 'BEGIN{FS=OFS="|"} {
    n = split($26, a, /[[:space:]]+/)
    $26=a[1]
    for(i=2; i<=n; i++)
        $26=$26""a[i]
}1' original.csv > final.csv

【讨论】:

  • 嗨。非常感谢,但这给了我“非法引用数组 a”的错误。
  • 啊,是的,您不能使用 GNU awk,因为在数组上使用 length 是 GNU awk 扩展。这里使用split 函数的返回值更有意义,因为这将是数组中元素的数量。查看工作版本的更新。
  • 我意识到 /[[:space:]]/ 没有给我任何结果,所以我尝试了 // 但即使这样,不改变的字段仍然是持久的。跨度>
  • @Mardwan 我的错,它实际上应该是[[:space:]]+。但是,如果由于某种原因您的 awk 不支持使用诸如 [[:space:]] 这样的 POSIX 字符类,您可以将其替换为 [\t ]+
  • 不幸的是,没有运气:(
猜你喜欢
  • 1970-01-01
  • 2013-07-14
  • 1970-01-01
  • 1970-01-01
  • 2017-08-08
  • 1970-01-01
  • 1970-01-01
  • 2012-11-23
  • 1970-01-01
相关资源
最近更新 更多