web-dev-qa-db-ja.com

正規表現の角括弧をgrepと一致させるにはどうすればよいですか?

[]の両方をgrepと一致させようとしていますが、[との一致に成功しました。どのように試しても、]に正しく一致させることができないようです。

コードサンプルは次のとおりです。

echo "fdsl[]" | grep -o "[ a-z]\+" #this prints fdsl
echo "fdsl[]" | grep -o "[ \[a-z]\+" #this prints fdsl[
echo "fdsl[]" | grep -o "[ \]a-z]\+" #this prints nothing
echo "fdsl[]" | grep -o "[ \[\]a-z]\+" #this prints nothing

編集:これを行う必要がある私の元の正規表現は、これです:

echo "fdsl[]" | grep -o "[ \[\]\t\na-zA-Z\/:\.0-9_~\"'+,;*\=()$\!@#&?-]\+" 
#this prints nothing

N.B: this postからのすべての回答を試しましたが、この特定のケースでは機能しませんでした。そして、[]内でそれらの括弧を使用する必要があります。

14
Jahid

POSIX正規表現仕様の BRE/ERE正規表現 セクションによると:

  1. [...]右角かっこ(']')は、リストの最初にある場合(最初の曲折アクセント記号('^')の後)、その特別な意味を失い、角かっこ式で表されます。それ以外の場合は、照合記号("[.].]"など)に表示されるか、照合記号、同値類、または文字クラスの右角かっこである場合を除き、角かっこ式を終了します。特殊文字'.''*''['、および'\'(それぞれ、ピリオド、アスタリスク、左角かっこ、および円記号)は、角かっこ式内で特別な意味を失います。

そして

  1. [...]角かっこ式で'-'']'の両方が指定されている場合、']'が最初に(存在する場合は'^'の後に)配置され、'-'が角かっこ式内で最後に配置されます。

したがって、正規表現は次のようになります。

echo "fdsl[]" | grep -Eo "[][ a-z]+"

+数量詞をサポートするEREの使用を指定するEフラグに注意してください。 + quantifierは、BRE(デフォルトモード)ではサポートされていません。

エスケープされた"[][a-z ]\+"を使用したMikeHoltの回答+の解決策は、GNU grepで実行されるため、機能します。 文法を拡張して\+をサポートし、1回以上繰り返すことを意味します 。これは実際には POSIX標準 による未定義の動作です(つまり、実装は意味のある動作を与えて文書化したり、構文エラーをスローしたりすることができます)。

コードをGNU環境でのみ実行できるという前提で問題がない場合は、MikeHoltの回答を使用しても問題ありません。例としてsedを使用すると、次のようになります。 POSIX sed (EREに切り替えるフラグなし)を使用するとBREでスタックし、POSIXBREで単純な正規表現を作成するのは面倒です。ここで定義されている数量詞は*だけです。 。

元の正規表現

grepは、入力ファイルを1行ずつ消費してから、その行が正規表現と一致するかどうかを確認することに注意してください。したがって、元の正規表現でPフラグを使用した場合でも、正規表現は行間で一致できないため、\nは常に冗長です。

水平タブに一致させることは可能ですがなしPフラグ ですが、このタスクにはPフラグを使用する方が自然だと思います。

この入力が与えられた場合:

$ echo -e "fds\tl[]kSAJD<>?,./:\";'{}|[]\\!@#$%^&*()_+-=~\`89"
fds     l[]kSAJD<>?,./:";'{}|[]\!@#$%^&*()_+-=~`89

質問の元の正規表現はほとんど変更せずに機能します(最後に+をエスケープ解除します)。

$ echo -e "fds\tl[]kSAJD<>?,./:\";'{}|[]\\!@#$%^&*()_+-=~\`89" | grep -Po "[ \[\]\t\na-zA-Z\/:\.0-9_~\"'+,;*\=()$\!@#&?-]+"
fds     l[]kSAJD
?,./:";'
[]
!@#$
&*()_+-=~
89

\n(上記で説明したように冗長であるため)とその他の不要なエスケープをいくつか削除できますが、次のようになります。

$ echo -e "fds\tl[]kSAJD<>?,./:\";'{}|[]\\!@#$%^&*()_+-=~\`89" | grep -Po "[ \[\]\ta-zA-Z/:.0-9_~\"'+,;*=()$\!@#&?-]+"
fds     l[]kSAJD
?,./:";'
[]
!@#$
&*()_+-=~
89
12
nhahtdh

1つの問題は、[が式の特殊文字であり、\でエスケープできないことです(少なくとも私のgrepのフレーバーでは)。解決策は、[[]のように定義することです。

7
skotka

regular-expressions.info によると:

ほとんどの正規表現フレーバーでは、文字クラス内の特殊文字またはメタ文字は、閉じ括弧(])、円記号(\)、キャレット(^)、およびハイフン(-)のみです。通常のメタ文字は文字クラス内の通常の文字であり、円記号でエスケープする必要はありません。

...そして.。

閉じ括弧(])、キャレット(^)、およびハイフン(-)は、円記号でエスケープするか、特別な意味を持たない位置に配置することで含めることができます。

したがって、grepでサポートされている正規表現構文の特定のフレーバーがこれに準拠していると仮定すると、"[ a-z[\]]\+"should 働いています。

ただし、私のバージョンのgrep(GNU grep 2.14)は、"[]"の最後にある"fdsl[]"のみをこの正規表現と一致させます。

ただし、その引用で言及されている他の手法を使用してみました(]を文字クラス内の通常の意味をとることができない位置に配置すると、うまくいったようです。

$ echo "fdsl[]" | grep -o "[][a-z ]\+"
fdsl[]
3
Mike Holt