awk正規表現で正規表現グループを参照する方法は?たとえば、正規表現グループがある場合は、(\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
答え1
busyboxの実装awk
は、私が知っている唯一の逆参照をサポートする実装です。と拡張もgawk
サポートします。gensub()
\w
sub()
と同様に、標準では値が1()の文字であり、その文字と一致する必要がありますが、(まあ)代わりにおよび代わりに使用する必要がありgsub()
ます。"..."
/.../
\\1
\1
awk
"\1"
^A
/\1/
"\\1"
以前は) は POSIX では指定されません。また、POSIX EREには逆参照はありません。この機能はBREにはありますが、EREにはありません。
$ echo ab aa cc de mn | busybox awk '{print gensub("(\\w)\\1", "\\1\\1\\1", "g")}'
ab aaa ccc de mn
busyboxはサポートされawk
ていませんが、グローバリゼーション、ロケールに関係なく(と同じ)一致し、\w
マルチバイト文字をサポートしません。a-zA-Z0-9_
[[:alnum:]]
$ echo ee éé | busybox awk '{print gensub("(\\w)\\1", "\\1\\1\\1", "g")}'
eee éé
sed
標準ユーティリティの場合、通常は作業に使用されます。
sed 's/\([[:alnum:]_]\)\1/&\1/g'
sed
正規表現は次のとおりです。基本的な逆参照された正規表現をサポートします。一部のsed
実装サポート拡大するPOSIXが標準の次のメジャーバージョンで指定するか、またはを含む正規表現はまだ参照を返しません(キャプチャリング-r
グループの代替エントリが指定されていても)。 GNUとbusyboxは逆参照をサポートしていますが、FreeBSDはサポートしていません。-E
-E
s
sed
-E
sed
答え2
$ 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も書けるという意味だ。
答え3
awk
これはおそらく質問の範囲外ですが、逆参照がサポートされていないのは、awk
常に次のものを使用するためです。本物正規表現、実装可能な式再帰なし有限状態機械によって。これらの実装はあらゆる種類の逆参照をサポートすることはできません(実装は単純ではありませんが、キャプチャグループをサポートできます)。
私の考えでは、awk
単純な時間とメモリの制限を一致させるために正規表現を使用する必要があります。
代わりに、perl / pcre / etcの "regexp"は、Turingシステムでのみ実装できる再帰的一致手順を説明する簡単な構文に進化しました。これはセキュリティに影響を与えます。信頼できないユーザーが正規表現を入力できる検索ボックスなどは、サービス拒否攻撃につながる可能性があり、そのような一致にどのくらいの時間やメモリが必要かを知ることはできません。厳格なランダム制限を実施し、持続的な豚を禁止するなどの措置を講じる必要があります。
これは古い記事これらすべてをより深く説明する著者Russ Cox。
答え4
残念ながら、POSIXや他の非busybox以外の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}"
gsub()を使用できます。char char
busybox awkを使用してこれを行う方法の詳細については、@Stephaneの回答を参照してください。