我有以下文本行结构:
3923 001 L05 LV,L05 RM
3923 002 L12 RA,L12 LA
3923 003 I06 ALL
3923 004 G04 RV,Z09 ALL
但我需要这个:
3923 001 L05 LV
3923 001 L05 RM
3923 002 L12 RA
3923 002 L12 LA
3923 003 I06 ALL
3923 004 G04 RV
3923 004 Z09 ALL
这可以通过正则表达式实现吗?
基本上,我需要将每一行复制包含“,”的次数,然后从第 10 个字符开始使其唯一;如果我能完成第一部分,那么只需每行的副本 x 逗号的数量,我就可以手动清理其余部分
答案1
考虑到您的示例的格式,这应该适用于初始大空格之后的任意数量的逗号分隔字符串(如果它是制表符,只需将第二个空格更改s///
为\t
sed ':;h;s/,.*//;p;x;s/ [^,]*,/ /;t;d' file
3923 001 L05 LV
3923 001 L05 RM
3923 002 L12 RA
3923 002 L12 LA
3923 003 I06 ALL
3923 004 G04 RV
3923 004 Z09 ALL
如果你想要标签那么
如果你想将制表符写为 \t,你可以使用 $'' 引号将其提供给 Bash: sed $':;h;s/,.*//;p;x;s/\t[^,] *,/ /;t;d'。或者只是插入一个文字选项卡(对于 bash,您需要键入 control-v 才能按字面意思输入)。 。
—托比·斯佩特
答案2
使用 sed 是可以的。将输入通过管道传输到下面。
| sed 's/\(^.\{12\}\)\([^,]\+\),\([^,]\+\)/\1\2\n\1\3/'
输出
3923 001 L05 LV
3923 001 L05 RM
3923 002 L12 RA
3923 002 L12 LA
3923 003 I06 ALL
3923 004 G04 RV
3923 004 Z09 ALL
这是处理带有多个“,”的输入的源
对于不带制表符的原始输入,请使用
| perl -ne '/,/ && do {chomp;s/^(.{12})(.+)/$1,$2/; @l = split(","); foreach $a (@l[1 .. $#l]) {print "$l[0]$a\n";};1;} || do {print;}'
如果输入有制表符,请使用
| perl -ne '/,/ && do{chomp; s/^([^\t]+\t)(.+)/$1,$2/; @l = split(","); foreach $a (@l[1 .. $#l]) {print "$l[0]$a\n";};1;} || do {print;}'
答案3
可能的解决方案awk
:
awk -F" " '{ x = $3 " " $4 " " $5; split(x, a, ","); for (i in a) { print $1, $2 "\t" a[i]; } }' file
输出应该是:
3923 001 L05 LV
3923 001 L05 RM
3923 002 L12 RA
3923 002 L12 LA
3923 003 I06 ALL
3923 004 G04 RV
3923 004 Z09 ALL
如果您的输入包含多个,
注释:3923 001 L05 LV,L05 RM,L09 AB
您可以尝试以下操作:
awk -F" " '{ x = $3; for (i = 4; i <= NF; i++) { x = x " " $i; } split(x, a, ","); for (i in a) { print $1, $2 "\t" a[i]; } }' file
答案4
您可以使用awk
字段分隔符并将其设置为空格或逗号。然后,以 2 个块为单位循环,将第一个和第二个字段与两个块一起打印:
$ awk -v FS='(\\s+|,)' '{for (i=3; i<=NF; i+=2) print $1, $2, $i, $(i+1)}' file
3923 001 L05 LV
3923 001 L05 RM
3923 002 L12 RA
3923 002 L12 LA
3923 003 I06 ALL
3923 004 G04 RV
3923 004 Z09 ALL