我在 CSV 文件中有这样的场景:
ID,PRICE,QUANTITY,ARRIVAL
01299,"41,5",1,0
26528,"412,03",0,0
38080,"2,35",0,0
38081,"2,35",0,0
..
..
我问自己的问题是:如何替换,
,.
但仅在价格中,用双引号括起来"..."
,在PRICE
列中?
我尝试过
sed -i 's/\(,\)[^ ]*\( .*\)/\1"."\2/'
但没有成功,你能给我一个提示吗?
答案1
我建议使用 sed 的“-E”选项来扩展正则表达式。如果引号之间只有数字,您可以执行以下操作:
~ $ cat foo
lorem, ipsum
"5,25", foobar
"foo,bar", foobar
~ $ cat foo | sed -E 's/"([0-9]+)\,([0-9]+)"/"\1.\2"/g'
lorem, ipsum
"5.25", foobar
"foo,bar", foobar
如果引号中包含大写和小写字母,则可以像这样扩展正则表达式:
~ $ cat foo | sed -E 's/"([0-9]+|[a-z]+|[A-Z]+)\,([0-9]+|[a-z]+|[A-Z]+)"/"\1.\2"/g'
lorem, ipsum
"5.25", foobar
"foo.bar", foobar
您可以在 regex101.com 轻松测试您的正则表达式:另请参阅:https://regex101.com/r/mlfSMp/1
答案2
使用csvformat
来自csvkit:
$ csvformat -D ';' file | tr , . | csvformat -d ';'
ID,PRICE,QUANTITY,ARRIVAL
01299,41.5,1,0
26528,412.03,0,0
38080,2.35,0,0
38081,2.35,0,0
上述命令将 CSV 分隔符从默认逗号更改为分号。然后,它将所有剩余的逗号更改为点,然后将字段分隔符更改回逗号。
或者,使用以下命令将 CSV 转换为 JSONcsvjson
并修改数据jq
:
$ csvjson -I file | jq -r '(.[0] | keys_unsorted | @csv), (map(.PRICE |= sub(",";".") | [.[]] | @csv)[])'
"ID","PRICE","QUANTITY","ARRIVAL"
"01299","41.5","1","0"
"26528","412.03","0","0"
"38080","2.35","0","0"
"38081","2.35","0","0"
csvformat
如果您想删除任何不需要的引号,请传递此参数(不带参数)。
该jq
表达式首先通过从输入数组中的第一个对象获取键来输出标头。然后,它修改PRICE
每个元素的字段(将逗号更改为点)并将值格式化为 CSV 以便输出。
第二个变体和第一个变体之间的效果差异在于我们只影响列PRICE
。任何其他字段中的任何嵌入逗号都将保持不变。
作为参考,考虑到问题中的 CSV 数据,从 获取的JSON 文档jq
为输入csvjson
[
{"ID":"01299","PRICE":"41,5","QUANTITY":"1","ARRIVAL":"0"},
{"ID":"26528","PRICE":"412,03","QUANTITY":"0","ARRIVAL":"0"},
{"ID":"38080","PRICE":"2,35","QUANTITY":"0","ARRIVAL":"0"},
{"ID":"38081","PRICE":"2,35","QUANTITY":"0","ARRIVAL":"0"}
]
答案3
调整这个回答到仅删除逗号分隔文件中引号之间的逗号解决方案awk
:
awk -F'"' -v OFS='"' '{ for (i=2; i<=NF; i+=2) gsub(",", ".", $i) } 1' infile
哪里infile
ID,PRICE,QUANTITY,ARRIVAL
01299,"41,5",1,0
26528,"412,03",0,0
38080,"2,35",0,0
38081,"2,35",0,0
结果是
ID,PRICE,QUANTITY,ARRIVAL
01299,"41.5",1,0
26528,"412.03",0,0
38080,"2.35",0,0
38081,"2.35",0,0
代码的解释与引用的答案相同,因此我不再重复,除了:
- 输出字段分隔符现在是
"
(即OFS='"'
),而不是空(即OFS=''
),并且; - now
gsub
将逗号 (","
) 替换为句点 ("."
),而不是空 (""
)