将 CSV 文件中的 SUBSTRINGS 剪切为特定长度

将 CSV 文件中的 SUBSTRINGS 剪切为特定长度

我有一个如下所示的文件,猫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",,

相关内容