我有一个如下所示的文件,猫Test.csv
"pav",12345,"ABCD,EF;xyz23;15rtg",,
"xyz",,"C4DEF;x23yu;rtg",,
修改后:
cat Test.csv
"pav",12345,"AB;xy;15",,
"xyz",,"C4;x2;rt",,
这3包含以“”分隔的子字符串的 rd 字段;
必须替换为其子字符串
答案1
以下是使用csvkit
,因为直接用 解析引用字段中包含逗号的 CSV 数据awk
很容易出错。
这将得到正确格式的第三列:
csvcut -c 3 file.csv |
sed -r 's/^"|"$//g' |
awk -F';' -vOFS=';' '{ for (i=1; i<=NF; ++i) $i = substr($i, 0, 2) } { printf("\"%s\"\n", $0) }' >tmp-3rd
对于给定的输入,这会产生
"AB;xy;15"
"C4;x2;rt"
csvcut
将剪切第三列。sed
将从数据中删除所有双引号(如果它们出现在行的第一个或最后一个)。- 该
awk
程序将遍历;
- 分隔的字段并将其缩减为每个字段两个字符的长度。它打印出带有双引号的数据。 - 输出被写入文件
tmp-3rd
。
然后只需将其与原始数据重新组装即可(这是假设bash
或任何其他可以使用 进行过程替换的 shell <(...)
):
paste -d, <( csvcut -c 1,2 file.csv ) tmp-3rd <( csvcut -c 4,5 file.csv ) | csvformat
paste
会将各列放在一起,中间用逗号分隔。- 第一个进程替换生成原始文件的前两列,第二个进程替换生成最后两列。在中间,我们提供修改后的第三列。
- 作为可选步骤,我们传递数据,
csvformat
根据需要引用或取消引用字段。
输出将是
pav,12345,AB;xy;15,,
xyz,,C4;x2;rt,,
绕过对临时文件的需要:
paste -d, \
<( csvcut -c 1,2 file.csv ) \
<( csvcut -c 3 file.csv | sed -r 's/^"|"$//g' |
awk -F';' -vOFS=';' '{ for (i=1; i<=NF; ++i) $i = substr($i, 0, 2) } { printf("\"%s\"\n", $0) }' ) \
<( csvcut -c 4,5 file.csv ) | csvformat
答案2
和perl
假设;
仅在第三个字段中
$ perl -pe 's/"\K[^;"]*;[^"]*(?=")/$&=~s|([^;]{2})[^;]+|$1|gr/e' ip.txt
"pav",12345,"AB;xy;15",,
"xyz",,"C4;x2;rt",,
"\K
匹配"
感兴趣的字符串之前和感兴趣的字符串之后(?=")
。"
但它们"
本身不是捕获字符串的一部分,因为这些是环视[^;"]*;[^"]*
匹配任何非;
或"
字符,后跟;
非"
字符$&=~s|([^;]{2})[^;]+|$1|gr
对匹配的字符串执行另一个替换e
修饰符允许在替换部分使用 Perl 代码
仅限制第三个字段
$ cat ip.txt
"pav",12345,"ABCD,EF;xyz23;15rtg",,
"xyz",,"C4DEF;x23yu;rtg",,
"foo;12,23;good",124,253
12,5232,"xyz","ijk;5545;62"
$ perl -pe 's/^("[^"]*",|[^,]*,){2}"\K[^;"]*;[^"]*(?=")/$&=~s|([^;]{2})[^;]+|$1|gr/e' ip.txt
"pav",12345,"AB;xy;15",,
"xyz",,"C4;x2;rt",,
"foo;12,23;good",124,253
12,5232,"xyz","ijk;5545;62"
答案3
准确且坚固Python3.x解决方案(基于csv.阅读器目的):
parse_csv.py
脚本:
import csv, sys
with open(sys.argv[1]) as f:
reader = csv.reader(f)
for l in reader:
l = [s if ';' not in s else ';'.join(_[:2] for _ in s.split(';')) for s in l]
print(','.join(i if not i or i.isnumeric() else '"{}"'.format(i) for i in l))
用法:
python3 parse_csv.py Test.csv
输出:
"pav",12345,"AB;xy;15",,
"xyz",,"C4;x2;rt",,
Python的模块为数据csv
提供了强大而灵活的支持。csv
答案4
复杂的GNUAWK
解决方案(解析csv
数据):
awk -v FPAT='"[^"]+"|[^",]+|,,' '{
for (i=1;i<=NF;i++) {
if ($i~/^".*;./) {
len=split($i,a,";"); v=substr(a[1],1,3);
for (j=2;j<=len;j++) v= v";"substr(a[j],1,2);
v=v"\042"
} printf "%s%s",(v? v: ($i~/^,,/? (i==NF? ",":""):$i )),
(i==NF? ORS:OFS); v=""
}
}' OFS=',' Test.csv
FPAT='"[^"]+"|[^",]+|,,'
- 定义字段值的复杂正则表达式模式if ($i~/^".*;./) ...
- 如果当前字段$i
包含;
字符len=split($i,a,";")
-通过分隔符将字段值拆分$i
为数组。分配有创建的元素/块的数量a
;
len
v=substr(a[1],1,3);
- 捕获所需长度的第一个块,包括前导"
字符,例如。"AB
将被提取自"ABCD,EF
for (j=2;j<=len;j++) ...
- 迭代剩余的块/项目v=v"\042"
- 将尾部双引号添加"
到已处理的序列中v
。\043
是表示双引号 char 的 ASCII 八进制代码"
。($i~/^,,/? (i==NF? ",":""):$i )
- 每个空字段均使用单个逗号和公共分隔符(也),,
重新创建。这是为了避免多余的逗号混乱,例如,
,
"pav",,,
(i==NF? ORS:OFS)
- 遇到最后一个字段时i==NF
- 打印输出记录分隔符ORS
,否则 - 打印输出字段分隔符OFS
输出:
"pav",12345,"AB;xy;15",,
"xyz",,"C4;x2;rt",,