異なるファイル内の同じ行にある複数の文字列パターンを、文字列と一致する番号で置き換えるためのawkスクリプト

Nov 26 2020

<>内の文字列を検索するawkスクリプトが必要です。文字列が見つからない場合は、インデックスカウンターの現在の値(最初は0)に置き換えて、カウンターをインクリメントする必要があります。<>内にすでに認識されている文字列が見つかった場合は、文字列のインデックスを検索して、そのインデックスに置き換える必要があります。これは複数のファイルにわたって実行する必要があります。つまり、プログラムの起動時にのみ、複数のファイルでパターンが検索されてもカウンターはリセットされません。例:file_a.txt:

123abc<abc>xyz
efg
<b>ah
a<c>, <abc>
<c>b
(<abc>, <b>)

file_b.txt:

xyz(<c>, <b>)
xyz<b>xy<abc>z

になるはずです

file_a_new.txt:

123abc<0>xyz
efg
<1>ah
a<2>, <0>
<2>b
(<0>, <1>)

file_b_new.txt:

xyz(<2>, <1>)
xyz<1>xy<0>z

私がこれまでに得たもの:

awk 'match($0, /<[^>]+>/) { k = substr($0, RSTART, RLENGTH)
   if (!(k in freq))
      freq[k] = n++
   $0 = substr($0, 1, RSTART-1) freq[k] substr($0, RSTART+RLENGTH) } { print $0 > (FILENAME ".tmp")
}' files

ただし、これは1行に1つの<>パターンしか検出できませんが、1行に複数の<>パターンが存在する可能性があります。では、どのようにコードを変更する必要がありますか?

編集:ファイルはeditetではなく、新しいファイルを作成する必要があります

回答

3 anubhava Nov 26 2020 at 17:31

文字列として使用gnu-awkすると、次のように簡単に使用できます。RS<key>

awk -v RS='<[^>]+>' '{ ORS="" }  # init ORS to ""
RT {                                        # when RT is set
   if (!(RT in freq))                       # if RT is not in freq array
      freq[RT] = n++                        # save n in freq & increment n
   ORS="<" freq[RT] ">"                     # set ORS to < + n + >
}
{
   print $0 > ("/tmp/" FILENAME)
}' file_{a,b}.txt
1 EdMorton Nov 26 2020 at 17:24

awkの使用:

$ cat tst.awk FNR == 1 { close(out) out = FILENAME ".tmp" } { head = "" tail = $0
    while ( match(tail,/<[^>]+>/) ) {
        tgt = substr(tail,RSTART+1,RLENGTH-2)
        if ( !(tgt in map) ) {
            map[tgt] = cnt++
        }
        head = head substr(tail,1,RSTART) map[tgt]
        tail = substr(tail,RSTART+RLENGTH-1)
    }
    print head tail > out
}

$ head file_*.tmp
==> file_a.txt.tmp <==
123abc<0>xyz
efg
<1>ah
a<2>, <0>
<2>b
(<0>, <1>)

==> file_b.txt.tmp <==
xyz(<2>, <1>)
xyz<1>xy<0>z