合并具有相同前三个字段的重复行

合并具有相同前三个字段的重复行

我有以下输入(一千行)。我想要一个sed命令将重复的行与相同的前三个字段合并添加仅不同的领域或删除“不适用”:

D04005;4;279;0;0;SSM-4-1
D04005;5;40;0;0;SSM-5-1
LE040A;1;363;(26.3);N/A;SM-1-1
LE040A;1;363;(27.4);N/A;SM-1-2

预期输出:

D04005;4;279;0;0;SSM-4-1
D04005;5;40;0;0;SSM-5-1
LE040A;1;363;(26.3);(27.4);SM-1-1/SM-1-2

答案1

sed ':n
    s|;N/A;|;|g;$!N
    s|^\(\([^;]*;\)\{3\}\)\(.*\)\n\1|\1\3;|;tn
    P;D
'   <<\IN
D04005;4;279;0;0;SSM-4-1
D04005;5;40;0;0;SSM-5-1
LE040A;1;363;(26.3);N/A;SM-1-1
LE040A;1;363;(27.4);N/A;SM-1-2
LE040A;1;363;(28.5);N/A;SM-1-3
LE040A;1;363;(29.6);N/A;SM-1-4
IN

对于输入中的每个序列,这将继续分支回test,仅合并每个序列的尾部。

这是可移植的,但是如果你可以使用的话,写起来会更容易一些-E扩展正则表达式(就像您可能使用 BSD 或 GNU 版本一样)...

sed -E ':n
        s|;N/A;|;|g;$!N
        s|^(([^;]*;){3})(.*)\n\1|\1\3;|;tn
P;D'

如果您想将所有内容都写在一行上:

sed -Ee:n -e's|;N/A;|;|g;$!N;s|^(([^;]*;){3})(.*)\n\1|\1\3;|;tn' -eP\;D

...会起作用,但我从来都不是很喜欢一句台词像那样...

无论如何,第一个的输出是:

输出

D04005;4;279;0;0;SSM-4-1
D04005;5;40;0;0;SSM-5-1
LE040A;1;363;(26.3);SM-1-1;(27.4);SM-1-2;(28.5);SM-1-3;(29.6);SM-1-4

还可以移动以 w/ 开头的任何尾随字段SM-到行尾,并用 分隔每个/,我相信以下应该有效:

sed -E ':n
        s|;N/A;|;|g
        s|;(SM-[^;]*)$|/\1|;$!N
        s|^(([^;]*;){3})(.*)\n\1|\1\3;|;tn
P;D'

顺便说一句,如果您能够更清楚、更具体地了解您的需求,这会变得更容易、更快。对我来说,您似乎不想只合并前三个相同的字段任何两个连续的行,并删除匹配的字段N/A任何线,然后移动SM-字段到尾部任何线。相反,对我来说,你所说的所有这些单独的工作实际上都是一样的,而且你真的想要这样的东西:

  • 如果发现输入行包含三个字母数字、分号分隔的字段,然后是一个带括号的浮点字段,后跟另一个冒号分隔符,然后是一个N/A领域,我们应该做到以下几点:
    1. 检查下一行是否也与此描述匹配,如果是,则比较当前行和下一行的前三个字段。
    2. 如果找到匹配项,则仅保留下一行的最后一个字段,然后递归重试。
    3. 无论如何,始终删除匹配的字段N/A,并将最后一个替换;/
  • 无论如何,将剩余的所有内容打印到标准输出。

你看出有什么不同了吗?它是根据单个初始条件执行的一系列任务。如果你能这么清楚,那么你的匹配就不必弥补你处理时间的普遍性。

如果我是正确的,那么以下可以工作:

sed '   \|;N/A;|!b
        s||/|;$!N
        \|^\(.*(\)\(.*)\)\(.*\)\(\n\1\)\(.*)\)|!P
        s||\4\2;(\5\3|;D
' <<\IN
D04005;4;279;0;0;SSM-4-1
D04005;5;40;0;0;SSM-5-1
LE040A;1;363;(26.3);N/A;SM-1-1
LE040A;1;363;(27.4);N/A;SM-1-2
LE040A;1;363;(28.5);N/A;SM-1-3
LE040A;1;363;(29.6);N/A;SM-1-4
IN

D04005;4;279;0;0;SSM-4-1
D04005;5;40;0;0;SSM-5-1
LE040A;1;363;(26.3);(27.4);(28.5);(29.6)/SM-1-1/SM-1-2/SM-1-3/SM-1-4

...这里是-E在一条线上...

sed -e'\|;N/A;|!b' -e's||/|;$!N;\|^\(.*(\)\(.*)\)\(.*\)\(\n\1\)\(.*)\)|!P;s||\4\2;(\5\3|;D'

...或在-E扩展语法...

sed -Ee'\|;N/A;|!b' -e's||/|;$!N;\|^(.*\()(.*\))(.*)(\n\1)(.*\))|!P;s||\4\2(\5\3|;D'

答案2

发射机:

@(repeat)
@  (cases)
@id;@f2;@f3;@val1;@nil;@sm1
@id;@f2;@f3;@val2;@nil;@sm2
@    (do (put-line `@id;@f2;@f3;@val1;@val2;@sm1/@sm2`))
@  (or)
@line
@    (do (put-line line))
@  (end)
@(end)

$ txr data.txr data
D04005;4;279;0;0;SSM-4-1
D04005;5;40;0;0;SSM-5-1
LE040A;1;363;(26.3);(27.4);SM-1-1/SM-1-2

答案3

sed -r ':a;N;s!;N/A!!g;s/^(([^;]*;){3})(.*)\n\1/\1\3;/;T;s!^(([^S][^;]*;){3,})(S*SM-[^;]*);(([^S][^;]*;){1,})(.*)!\1\4\3/\6!;ta' inputfile

尽管输出中仅 6 个字段的注释的隐含数学表明只有对,但这是循环版本,匹配时对输出 SM-1-1/SM-1-2 进行了更改。

相关内容