如何编写 a sed(或awk,或两者),它将重写以下内容:
echo 'v100 v201 v102 v300 v301 v500 v999 v301' | sed/awk ...
Run Code Online (Sandbox Code Playgroud)
到这个输出:
v1 v2 v3 v4 v5 v6 v7 v5
Run Code Online (Sandbox Code Playgroud)
即每个后续的都vx被重写以开始并且在序列中使用v1...vn相同的地方(即)应该应用相同的(如)。vv301vv5
旁注:示例输入序列显示了所有可能的情况(即重复、原始数据乱序、原始数字跳跃)。
您是可以回答这个问题的 sed 或 awk 专家吗?
和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
Run Code Online (Sandbox Code Playgroud)
v\d+匹配v后跟一个或多个十进制数字。after重置匹配部分的开始,保留其左侧\K的内容,以便仅替换数字序列。vKvse标志导致替换被视为被评估以产生替换的代码。e在该代码中,$&包含匹配的部分。A // B是OR的一种形式,它扩展为AifA已定义,B否则(与此相反A || B,它扩展为AifA解析为真值,B否则)。//=是相应的作业形式。SoA //= B是 的缩写if (defined(A)) {A} else {A = B}。请注意,$seen哈希表是根据这些数字的字符串值进行索引的,因此v2 v02 v002,您将得到v1 v2 v3、2和02,002它们是彼此不同的字符串。您可以替换$&为0+$&来标准化数字(010 被视为 10,而不是八进制 8),以便进入v1 v1 v1上面的示例。或者你可以s{v0*\K\d+}{$seen{$&} //= ++$n}ge保留前导0s 并得到v1 v01 v001结果。
为了避免替换v1在rev1sion例如中找到的内容,您可以在匹配项 ( ) 的两侧添加一些单词b边界\bv\K\d+\b正则表达式运算符。或者仅替换以空格分隔的单词(v1.2例如,单独保留),为非白色步伐添加一些负面的环视: 。S(?<!\S)v\K\d+(?!\S)
使用awk:
awk '{ for (i=1; i<=NF; ++i) $i = (seen[$i] ? seen[$i] : seen[$i] = "v" ++n) }; 1'
Run Code Online (Sandbox Code Playgroud)
这将遍历每个输入行的所有字段并重新分配它。重新分配的值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
Run Code Online (Sandbox Code Playgroud)
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'
Run Code Online (Sandbox Code Playgroud)
或者,为了可读性,格式化为多行:
awk '
{
for (i=1; i<=NF; ++i)
if ($i ~ "^v[0-9]+$")
$i = (seen[$i] ? seen[$i] : seen[$i] = "v" ++n)
}; 1'
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
518 次 |
| 最近记录: |