【问题标题】:Remove ":" from field two of CSV only and ignore other fields仅从 CSV 的第二个字段中删除“:”并忽略其他字段
【发布时间】:2016-05-21 14:54:35
【问题描述】:

我一直在尝试清理 csv 文件中的数据,其中包含类似于以下的数据:

8979880, Number One : Exclusive Mix, 387387, http://www.smashhits.com
4844404, Top 40 : 1988, 3893938, http://www.best80s.com
48094940, Highlander:The Return, 489494, http://www.instantaccess.com 

我的目标是用空格替换字段 2 中的冒号。最初,我使用 sed 将 : 替换为类似空格的,因此:

sed i "s/:/ /g" file.csv

这适用于删除冒号,但不幸的是,这也删除了 url 中的冒号,这不是我想要的。如何指定我只希望命令影响字段 2 中的数据?

【问题讨论】:

    标签: regex linux bash csv sed


    【解决方案1】:

    使用 awk 你可以做到

    awk '/:/{sub(/:/, " ")} 1' file.csv
    

    /:/ 匹配第一次出现的 :

    {sub(/:/, " ")} 替换 : 用空格

    1 只是打印该行。

    【讨论】:

    • 非常优雅!当被要求进行“简单”替换时,我总是忘记使用 awk。
    • 唯一的问题是,如果有一个没有 : 的标题,那么第一次出现的会变成 : 在 url 中
    • @abbie : 不在 $2 中的问题可以通过 beeing more specific 来解决,如下所示:awk -F, -v 'OFS=","' '$2 ~/:/ {gsub(/:/, " ", $2)} 1' file.csv。我们告诉 awk 使用: 作为字段分隔符并将条件和替换限制为$2。唉,那么我们必须告诉 awk 也使用 , 作为输出字段分隔符 (OFS)。
    • 是的,这个解决方案承认参数的数量和模式总是相同的。
    【解决方案2】:

    你可以像这样使用 gnu sed:

    sed -r 's/^([^,]*,[^,]*):/\1 /g' file.csv
    

    说明

    • ^ 将表达式锚定在每行的开头
    • 现在[^,]*, 匹配包含分隔符的第一个字段
    • 然后[^,]*:从第二个字段匹配到:
    • 括号^(...): 确保第二个字段中直到但不包括: 的所有内容都被捕获到\1
    • 最后用\1 替换(\1 后面有一个空格将: 替换为正则表达式匹配的行上的空格

    【讨论】:

    • 这实际上是完美的,它正好抓住了 OP 想要的第二个字段。
    • 通过像这样添加分支和标签:sed -r ':b s/^([^,]*,[^,]*):/\1 /g; t b',我们还可以在第二个字段中处理多个:
    • 正确,感谢 Lars,这太完美了,感谢您提供额外信息来解释每段代码的作用
    • 我刚刚也尝试将其应用于第二个字段中的句号,将同一代码中的“:”替换为“。”但这似乎没有按预期工作
    • 小心简单的解决方案; CSV 允许在(引用的)字段中使用逗号。可能适用于原始示例数据,也可能不适用。
    猜你喜欢
    • 2013-09-30
    • 1970-01-01
    • 2020-07-19
    • 2020-05-16
    • 2017-10-06
    • 1970-01-01
    • 2020-07-30
    • 1970-01-01
    • 2018-02-12
    相关资源
    最近更新 更多