如何编写 a sed
(或awk
,或两者),它将重写以下内容:
echo 'v100 v201 v102 v300 v301 v500 v999 v301' | sed/awk ...
到这个输出:
v1 v2 v3 v4 v5 v6 v7 v5
即每个后续的vx
都被重写以开始并且在序列中使用v1...vn
相同的地方(即)应该应用相同的(如)。v
v301
v
v5
旁注:示例输入序列显示了所有可能的情况(即重复、原始数据乱序、原始数字跳跃)。
您是可以回答这个问题的 sed 或 awk 专家吗?
答案1
使用awk
:
awk '{ for (i=1; i<=NF; ++i) $i = (seen[$i] ? seen[$i] : seen[$i] = "v" ++n) }; 1'
这将遍历每个输入行的所有字段并重新分配它。重新分配的值后面v
跟着 counter 的下一个值n
,除非之前已经见过该字段的值,在这种情况下,其新值将与之前给出的该字段的值相同。
最后1
的 触发修改行的输出。
测试:
$ echo 'v100 v201 v102 v300 v301 v500 v999 v301' | awk '{ for (i=1; i<=NF; ++i) $i = (seen[$i] ? seen[$i] : seen[$i] = "v" ++n) }; 1'
v1 v2 v3 v4 v5 v6 v7 v5
awk
仅当字段与正则表达式匹配时才修改字段的替代命令^v[0-9]+$
:
awk '{ for (i=1; i<=NF; ++i) if ($i ~ "^v[0-9]+$") $i = (seen[$i] ? seen[$i] : seen[$i] = "v" ++n) }; 1'
或者,为了可读性,格式化为多行:
awk '
{
for (i=1; i<=NF; ++i)
if ($i ~ "^v[0-9]+$")
$i = (seen[$i] ? seen[$i] : seen[$i] = "v" ++n)
}; 1'
答案2
和perl
:
$ echo 'v100 v201 v102 v300 v301 v500 v999 v301' |
perl -pe 's{v\K\d+}{$seen{$&} //= ++$n}ge'
v1 v2 v3 v4 v5 v6 v7 v5
v\d+
匹配v
后跟一个或多个十进制数字。 after\K
重置v
匹配部分的开始,K
保留其左侧的内容v
,以便仅替换数字序列s
。- 该
e
标志导致替换被视为代码对其e
进行评估以生产替代品。在该代码中,$&
包含匹配的部分。 A // B
是一种形式或者扩展为A
ifA
被定义,B
否则(与A || B
它扩展为A
ifA
解析为相反)真的值和B
其他)。//=
是相应的作业形式。 SoA //= B
是 的缩写if (defined(A)) {A} else {A = B}
。
请注意,$seen
哈希表的索引是细绳这些数字的值,依此类推,v2 v02 v002
您将得到、和 ,它们是彼此不同的字符串。您可以替换为来标准化数字(010 被视为 10,而不是八进制 8),以便进入上面的示例。或者你可以保留前导s 并得到结果。v1 v2 v3
2
02
002
$&
0+$&
v1 v1 v1
s{v0*\K\d+}{$seen{$&} //= ++$n}ge
0
v1 v01 v001
为了避免替换例如v1
中找到的内容rev1sion
,您可以添加一些词b
边界匹配两边的正则表达式运算符 ( \bv\K\d+\b
)。或者仅替换以空格分隔的单词(v1.2
例如,单独保留),添加一些消极环视对于非白人S
步伐:(?<!\S)v\K\d+(?!\S)
.
答案3
GNU 实现awk
支持RS
将其定义为正则表达式并将其匹配的内容记录在RT
特殊变量中。因此,有了它,您可以执行以下操作:
$ echo 'v100 v201 v102 v300 v301 v500 v999 v301' |
gawk -v RS='v[0-9]+' -v ORS= '
RT {$0 = $0 "v" (RT in seen ? seen[RT] : seen[RT] = ++n)}1'
v1 v2 v3 v4 v5 v6 v7 v5
请注意,它会替换所有出现的v
后跟数字的情况,甚至是在单词(如 inrev1.2
或 )中找到的数字rev0lution
。像我的 Perl 方法,如果数字可能是零填充的,您可能需要调整它。
答案4
仅限 GNU awk:
echo 'v100 v201 v102 v300 v301 v500 v999 v301' |
awk -v RS='[[:space:]]' -F '' '
$0 {printf "%s", $1 (A[$0]?A[$0]:A[$0]=++i) RT}'
v1 v2 v3 v4 v5 v6 v7 v5