【问题标题】:Update Delimiter of Specific Columns in Shell更新 Shell 中特定列的分隔符
【发布时间】:2021-05-05 13:25:45
【问题描述】:

我有一个 CSV 文件,CSV 文件中的列数是 10。但是这个值中有一个包含 "," 的列。我想将文件的分隔符更改为 "|" 而不更改包含 ","

的列中的数据

我有的文件

John Doe,19,England,3653,Manchester, England,Main Worker,20-05-1995

Bill Mark,19, Australia,3653,Main Street, People Two, Perth,Main Worker,20-05-1995

Mark Home,19,USA,3653, Redmond, Ground Town, Main Street, Virginia,Main Worker,20-05-1995

需要的输出

John Doe|19|England|3653|Manchester, England|Part Time Worker|20-05-1995

Bill Mark|19|Australia|3653|Main Street, People Two, Perth|Main Worker,20-05-1995

Mark Home|19|USA|3653| Redmond, Ground Town, Main Street, Virginia|Main Worker|20-05-1995

我尝试了多种解决方案,但无法实现我想要的。我尝试了以下命令,它只更新前 4 列的分隔符。

sed 's/,/|/;s/,/|/;s/,/|/;s/,/|/' file

我正在寻找的方法是更新前 4 列和后 2 列的分隔符。通过这种方式,我可以让文件具有更新的分隔符,并且地址列对其没有影响。

【问题讨论】:

  • 您的输入输出文件不匹配。

标签: bash shell delimiter


【解决方案1】:

使用 sed (GNU sed) 4.7:

sed 's/, /\o0/g;s/,/|/g;s/\d0/, /g' file

文件中的字段分隔符是逗号,但某些字段中可以有逗号。
正如您在数据中看到的那样,字段中的逗号永远不会单独出现。
幸运的是,它后面总是有一个空格。
所以首先,将 ', ' 转换为 char NUL (\o0]。这个 char 永远不会出现在文本文件中。
之后,将所有逗号转换为 '|'
最后恢复','

或者,使用 GNU Awk 5.1.0,API:3.0(GNU MPFR 4.1.0,GNU MP 6.2.1)

awk -F', ' 'BEGIN{OFS=FS}{for(i=1;i<=NF;i++)gsub(",","|",$i)}1' file

【讨论】:

  • 你能解释一下这个命令是如何工作的吗?那么如果想将相同的命令应用于更大的数据集,它将如何工作?
  • @Moiez。更大的数据集是什么意思?我认为它有效。
【解决方案2】:

从给出的简单示例中,您要保留的逗号是唯一后跟空格的逗号。

$: cat foo
Name,Age,Country,ID,Address,Category,DOB
John Doe,19,England,3653,Manchester, England,Main Worker,20-05-1995
Bill Mark,19, Australia,3653,Main Street, People Two, Perth,Main Worker,20-05-1995
Mark Home,19,USA,3653, Redmond, Ground Town, Main Street, Virginia,Main Worker,20-05-1995

$: sed -E 's/,(\S)/|\1/g' foo
Name|Age|Country|ID|Address|Category|DOB
John Doe|19|England|3653|Manchester, England|Main Worker|20-05-1995
Bill Mark|19, Australia|3653|Main Street, People Two, Perth|Main Worker|20-05-1995
Mark Home|19|USA|3653, Redmond, Ground Town, Main Street, Virginia|Main Worker|20-05-1995

这会扫描一个逗号后跟一个非空格,并记住后面的字符。
它将匹配的逗号(以及以下已保存的字符)替换为管道(以及以下已保存的字符)。它将忽略逗号后跟一个空格,因为它们与模式不匹配。

这仍然适用于所有提供的示例。
对于逗号后没有空格的情况,您将不得不重新构建该行。

$: cat foo
Name,Age,Country,ID,Address,Category,DOB
John Doe,19,England,3653,Manchester, England,Part Time Worker,20-05-1995
Bill Mark,19, Australia,3653,Main Street, People Two, Perth,Main Worker,20-05-1995
Mark Home,19,USA,3653, Redmond, Ground Town, Main Street, Virginia,Main Worker,20-05-1995

$: cat tst
while IFS=, read -a line;                                  # read and split
do set -- "${line[@]}"                                     # set as $1, etc
   for i in 0 1 2 3; do printf "%s|" "$1"; shift;  done;   # print first 4
   while (( 3 < $# )); do printf "%s, " "$1"; shift; done  # all BUT last 3
   printf "%s|" "$1" "$2"                                  # last 2 get |
   echo "$3"                                               # last 1 gets \n
done<foo

$: ./tst
Name|Age|Country|ID|Address|Category|DOB
John Doe|19|England|3653|Manchester,  England|Part Time Worker|20-05-1995
Bill Mark|19| Australia|3653|Main Street,  People Two,  Perth|Main Worker|20- 05-1995
Mark Home|19|USA|3653| Redmond,  Ground Town,  Main Street,  Virginia|Main Worker|20-05-1995

请注意,这样做会保留字段上的前导空格。如果你想剥离那些你需要手动完成的,但你可以在整个文件中一次性完成:

sed -E 's/[|]\s+/\|/g' file 

如果你真的想修剪所有字段上的所有前导/尾随空格 -

sed -E 's/^\s+//; s/\s+[|]\s+/\|/g; s/\s+$//;' file 

例如:

$: ./tst|    sed -E 's/[|]\s+/\|/g'
Name|Age|Country|ID|Address|Category|DOB
John Doe|19|England|3653|Manchester,  England|Part Time Worker|20-05-1995
Bill Mark|19|Australia|3653|Main Street,  People Two,  Perth|Main Worker|20-05-1995
Mark Home|19|USA|3653|Redmond,  Ground Town,  Main Street,  Virginia|Main Worker|20-05-1995

【讨论】:

  • 感谢您的解决方案,但问题是地址列中的逗号数量并不总是相同。它们是可变的,现在它们总是出现在空格字符之前。我在问题中添加了更多示例,您能否检查它们并提出相应的解决方案?
【解决方案3】:

您可以使用 awk。这种脚本可以完成这项工作:

t='John Doe,19,England,3653,Manchester, England,Main Worker,20-05-1995'
echo $t | awk '{ORS="";N=split($0,a,",");\
            print a[1]"|"a[2]"|"a[3]"|"a[4]"|"; \
            for(i=5;i<N-1;i++) print a[i]; 
            print "|"a[N-1]"|"a[N] }'

【讨论】:

  • 非常感谢您的回答,但此脚本正在删除英国曼彻斯特之间的逗号。我不希望它被删除。有什么办法可以保留吗?谢谢
猜你喜欢
  • 1970-01-01
  • 2021-11-12
  • 2020-09-06
  • 2020-07-25
  • 1970-01-01
  • 2017-06-28
  • 1970-01-01
  • 1970-01-01
  • 2017-03-17
相关资源
最近更新 更多