将在列中找到的正则表达式匹配添加到最后一列

Adding regex match found in column to last column

在 bash 中使用 perl、sed 或 awk,我需要在 csv 第 3 列中找到正则表达式模式并将其添加到最后一列 4。

例如,转这个:

2020/10/26,249.00,Test10028
2020/10/24,569.00,Test 00074
2020/10/24,1999.00,0016 1708fqb8ba
2020/10/24,1399.00,00450 165058hb1bda
2020/10/23,399.00,Att-10170 158bb8ba
2020/10/22,599.00,Ref:10150 1605fk0bsf
2020/10/22,5669.00,1605fk0bsf

进入这个:

2020/10/26,249.00,Test10028,10028
2020/10/24,569.00,Test 00074,00074
2020/10/24,1999.00,0016 1708fqb8ba,0016
2020/10/24,1399.00,00450 165058hb1bda,00450
2020/10/23,399.00,Att-10170 158bb8ba,10170
2020/10/22,599.00,Ref:10150 1605fk0bsf,10150
2020/10/22,5669.00,1605fk0bsf,

我发现的 PCRE 正则表达式过滤了我需要的东西(只有数字,长度 4-5,以 0-1 开头,没有尾词。):

(?<!\d)[0-1]\d{3,4}(?!\w)

在 akw 或 sed 中使用它不起作用。我试过的一些代码:

awk -F, 'match(, /(?<!\d)[0-1]\d{3,4}(?!\d)/, a) {print a[0]"," }' file.csv
sed -re 's/(?<!\d)[0-1]\d{3,4}(?!\d)/g' file.csv

但是 perl 确实给我结果使用:

perl -pe 's/(?<!\d)[0-1]\d{3,4}(?!\w)/!!!!/g' file.csv
2020/10/26,249.00,Test!!!!
2020/10/24,569.00,Test !!!!
2020/10/24,!!!!.00,!!!! 1708fqb8ba
2020/10/24,!!!!.00,!!!! 165058hb1bda
2020/10/23,399.00,Att-!!!! 158bb8ba
2020/10/22,599.00,Ref:!!!! 1605fk0bs

我们可以使用 -F, -a 引起 @F = split /,/ 以便与第三个字段一起使用并创建第四个字段。

perl -F, -pale'($F[3]) = $F[2] =~ /(?<!\d)([0-1]\d{3,4})(?!\w)/; $_=join(",", @F)'

你可以使用这个 GNU awk:

rx='([^0-9]|^)([01][0-9]{3,4})([^[:alnum:],][^,]*)?$'
awk -v r=$rx 'BEGIN{FS=OFS=","} {print ( ~ r) ? [=10=] OFS gensub(r, "\1\2\3,\2", 1, ) : [=10=] OFS}' file.csv > newfile.csv

参见 online sed demo (and the regex demo)。

详情

  • ([^0-9]|^) - 第 1 组:任何非数字字符或字符串开头
  • ([01][0-9]{3,4}) - 第 2 组:01,然后是三位或四位数字
  • ([^[:alnum:],][^,]*) - 数字、字母和逗号以外的字符的可选序列,然后是逗号以外的零个或多个字符。
  • $ - 字符串结尾。
  • , - 替换是组 1、2、3、逗号和组 2 值的串联。

awk命令:

  • -v r=$rx - 将正则表达式 $rx 作为变量 r 传递给 awk 脚本
  • BEGIN{FS=OFS=","} - 将输入和输出字段分隔符设置为逗号
  • {print ( ~ r) ? [=24=] OFS gensub(r, "\1\2\3,\2", 1, ) : [=24=] OFS} - 如果正则表达式匹配字段 3,gensub 的结果将附加到整行(记录)的逗号之后,否则仅附加逗号
  • gensub(r, "\1\2\3,\2", 1, ) 替换字段 3 中第一次出现的模式。

您不需要 gnu-awk 即可完成。它在正则表达式中有点冗长,但它完成了工作:

nice gcat test.csv \
\
| mawk2 'BEGIN { FS=OFS="," 
    
  } ((~/^[^0-9]*[0-1][0-9]                      \
             [0-9][0-9][0-9]?($|[^[:alpha:]])/) && \
                                                    \
    (($++NF=)+gsub(/^[^0-9]*|[ ].*$/,"",$NF))) || 1'

2020/10/26,249.00,Test10028,10028
2020/10/24,569.00,Test 00074,00074
2020/10/24,1999.00,0016 1708fqb8ba,0016
2020/10/24,1399.00,00450 165058hb1bda,00450
2020/10/23,399.00,Att-10170 158bb8ba,10170
2020/10/22,599.00,Ref:10150 1605fk0bsf,10150
2020/10/22,5669.00,1605fk0bsf

这纯粹是假设输入是干净的,并且不会在应用过滤器之前尝试执行任何类型的数据清理。