Awk regexで正規表現グループを参照するにはどうすればよいですか?たとえば、正規表現グループ(\w)
がある場合、(\w)\1
のように同じ正規表現で後でそれをどのように参照できますか? awkはこの機能をサポートしていますか?以下の例は機能しません。
# In this example, I want to change aa to aaa and cc to ccc.
echo ab aa cc de mn | gawk '{print gensub(/(\w)\1/, "\\1\\1\\1", "g")}'
# The result is: ab aa cc de mn
# The expected result is: ab aaa ccc de mn
$ echo ab aa cc de mn | Perl -pe 's/(\w)\1/\1\1\1/g'
ab aaa ccc de mn
時々、あなたはawkができないことがいくつかあるが、Perlはできることを受け入れる必要があります。
明るい面を言えば、awk
を十分に使い、gensub
を使用して後方参照を行いたい場合は、Perl
がドドルであることがわかります。つまり、awkを記述できる場合は、Perlを記述できます。
これは問題を超えているかもしれませんが、awk
が後方参照をサポートしていない理由は、awk
が常に使用されているためですreal正規表現、つまり、有限状態マシンによって再帰なしで実装できる正規表現。このような実装は、いかなる形式の後方参照もサポートできません(実装は単純ではありませんが、キャプチャグループをサポートできます)。
私が見るようにawk
を使用するアイデアは、正規表現を使用して、時間とメモリの範囲が制限されていない一致と、それより複雑なものにはCのような完全な言語を使用することです。
逆に、Perl/pcre /などからの「正規表現」は、チューリングマシンでのみ実装できる再帰的なマッチング手順を記述するコンパクトな構文に成長しました。これはセキュリティに影響します。信頼できないユーザーがそのような正規表現を入力できる検索ボックスなどは、サービス拒否攻撃への招待です。そのような試合にかかる時間やメモリを誰も知ることはできず、ハードな任意の制限や永続的な豚の禁止などの総計のみが可能です。
以下は、Russ Coxによる 古い記事 です。ここでは、これらすべてについて詳しく説明しています。
正規表現ではありませんが、動作します。 Wordのすべての文字が同じである場合、1文字追加します。
echo ab aa cc de mn | \
awk '{
for(i=1;i<=NF;i++)
{
char=substr($i,1,1)
for(j=2;j<=length($i);j++)
{
if(substr($i,j,1)==char) y=1
else
y=0
char=substr($i,j,1)
}
if(y) $i=$i""char
}
print $0
}'
ab aaa ccc de mn #output
残念ながら、POSIXまたは他の非ビジーボックスawkでは、正規表現内では後方参照がサポートされていないため、各行のすべての一意の文字でループを必要とします。
$ cat tst.awk
{
old = new = $0
while (old != "") {
char = substr(old,1,1)
gsub(char,"",old)
if ( char ~ /[[:alnum:]_]/ ) {
gsub(char char,char char char,new)
}
}
print new
}
$ echo ab aa cc de mn | awk -f tst.awk
ab aaa ccc de mn
上記は、ターゲット文字がこの場合のように正規表現メタ文字でない場合に機能します。それらがREメタ文字である可能性がある場合は、gsub()の正規表現コンテキストで使用する前にエスケープする必要があります。 char"{2}"
の代わりに char char
必要に応じてgsub()正規表現で。
Busybox awkでこのタスクを実行する方法については、@ Stephaneの回答を参照してください。