Bash: sed または awk 数値シーケンスの書き換え

Bash: sed または awk 数値シーケンスの書き換え

次を書き換えるsed(または両方)作成する方法:awk

echo 'v100 v201 v102 v300 v301 v500 v999 v301' | sed/awk ...

この出力に:

v1 v2 v3 v4 v5 v6 v7 v5

つまり、各後続の項目はvx最初から書き直され、同じ項目がシーケンスで使用される場合v1...vn(つまり)同じ項目が適用される必要があります。vv301vv5

注:入力シーケンスの例は、可能なすべての例(重複、順序が正しくないソースデータ、ソース番号ジャンプ)を示しています。

この質問に答えることができるsedまたはawkの専門家ですか?

答え1

使用awk:

awk '{ for (i=1; i<=NF; ++i) $i = (seen[$i] ? seen[$i] : seen[$i] = "v" ++n) }; 1'

その後、各入力行のすべてのフィールドを繰り返し再割り当てします。再割り当てされた値vの後には、カウンタの次の値が続きます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の後に1つ以上の10進数が続きます。その後、一致する部分の開始を\Kリセットし、一連の数字のみが置き換えられるように内容を左に置きます。vKvs
  • このeフラグを使用すると、置換は次のように処理されます。パスワード評価してe代替案を作成してください。このコードには$&一致する部分が含まれています。
  • A // B形式であるまたはAifが他にA定義されている場合に拡張されます(ifが次に拡張されるのとはB反対)。A || BAA本物値などB)。//=対応する割り当てフォームです。A //= Bの略語も同じだif (defined(A)) {A} else {A = B}

$seenハッシュテーブルのインデックスは次のとおりです。ひもこの数値などの値は、v2 v02 v002異なる文字列である、およびを取得します。上記の例に代わって、数値(010は8進数8ではなく10として扱われます)を正規化できます。あるいは、先行sを維持し、結果を得ることができます。v1 v2 v3202002$&0+$&v1 v1 v1s{v0*\K\d+}{$seen{$&} //= ++$n}ge0v1 v01 v001

v1たとえば、見つかった内容を置き換えたくない場合は、rev1sion次のように追加できます。単語bの境界\bv\K\d+\b両方と一致する正規表現演算子()。または、スペースで区切られた単語を置き換え(v1.2例:単独で残す)など、いくつか追加します。否定的な視線白以外のS速度の場合:(?<!\S)v\K\d+(?!\S)

答え3

GNU実装はこれを正規表現として定義し、特殊変数に一致を書き込むことをawkサポートします。したがって、これを使用して次のことができます。RSRT

$ 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数字の後に続くすべての項目に代わるものであり、rev1.2単語(inまたはなど)内の偶数の数字も置き換えます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

関連情報