web-dev-qa-db-ja.com

FreeBSDには基本的な正規表現の複数のバリアントが含まれていますか?

grepsedはどちらも、デフォルトで「基本正規表現」(「BRE」)を使用するものとして説明されています。 BREはよく説明されています ここ

しかし、この出力を考慮してください:

_# echo '    aaaaa   ' | grep '\(aaaaa\|bbbbb\)'
    aaaaa
# echo '    aaaaa   ' | sed '/\(aaaaa\|bbbbb\)/ s/ /_/g'
    aaaaa
_

最初のコマンドでは、出力がgrepを渡したため、\( ... \| ... \)構文は_(X OR Y)_として明確に機能しました

2番目のコマンドでは、スペースが変更されなかったため、\( ... \| ... \)構文は明らかに_(X OR Y)_として機能しません。アンダースコアに。

(対照的に、bothコマンドは_\+_を「1回以上の繰り返し」として認識します)

何が起こったの? FreeBSDには2つのフレーバーのBREがあるように見えるのはなぜですか。一方は構文を認識し、もう一方は認識しません。

より深い疑問は、多くのプロジェクトが他のUNIXライクなシステムへの移植性を提供するためにBREを検討することです。しかし、これは、BREが個々のプラットフォーム内で同じでなければ、プラットフォーム間で同じである可能性は低いことを示唆しています。あれ?

5
Stilez

リンク先の記事の説明が間違っています。

実際のPOSIX定義 は次のように述べています。

エスケープされていない<backslash>( '\')が前にある通常の文字の解釈は、以下を除いて未定義です。 [(){}、数字および括弧式内]

また、通常の文字は、BRE特殊文字.[^$*およびバックスラッシュ自体を除いて、任意のものとして定義されます。

そのため、そのページのクレームとは異なり、\+はBREで未定義であり、\|も未定義です。

一部の正規表現の実装では、これらをERE +および|と同じように定義していますが、特にGNU ones。ですが、それを当てにしないでください。代わりに機能。

もちろん、ここでの問題は、ERE代替演算子|がBREにまったく存在せず、ERE +と同等のものが醜く醜いことです(\{1,\}です)。したがって、おそらく代わりにEREを使用する必要があります。

9
ilkkachu
$ echo '    aaaaa   ' | sed 's/aaaaa|bbbbb/_/g'
    aaaaa
$ echo '    aaaaa   ' | sed -E 's/aaaaa|bbbbb/_/g'
    _
$ echo '    aaaaa   ' | sed -r 's/aaaaa|bbbbb/_/g'
    _
$ echo '    aaaaa   ' | sed -E '/(aaaaa|bbbbb)/ s/ /_/g'
____aaaaa___
$ echo '    aaaaa   ' | sed -E '/aaaaa|bbbbb/ s/ /_/g'
____aaaaa___

orはBRE(基本正規表現)ではありません。 extendedBREには-Eを指定する必要があります。

GNUまたはBSD Sed)==の Regex代替/または演算子(foo | bar)を参照

更新

なぜgrepは機能したのですか?

grep を使用して、使用するパターンの種類を選択できます。

  -E, --extended-regexp     PATTERN is an extended regular expression
  -F, --fixed-strings       PATTERN is a set of newline-separated strings
  -G, --basic-regexp        PATTERN is a basic regular expression
  -P, --Perl-regexp         PATTERN is a Perl regular expression
  -e, --regexp=PATTERN      use PATTERN as a regular expression

これらのスイッチを使用すると、grepが実際にデフォルトでBREを実行し、OP式がEREで失敗することがわかります。

$ echo '    aaaaa   ' | grep '\(aaaaa\|bbbbb\)'
    aaaaa
$ echo '    aaaaa   ' | egrep '\(aaaaa\|bbbbb\)'
$ echo '    aaaaa   ' | grep -E '\(aaaaa\|bbbbb\)'
$ echo '    aaaaa   ' | grep -G '\(aaaaa\|bbbbb\)'
    aaaaa
$ echo '    aaaaa   ' | grep -G 'aaaaa\|bbbbb'
    aaaaa
$ echo '    aaaaa   ' | grep -G 'aaaaa|bbbbb'
$ echo '    aaaaa   ' | grep -E 'aaaaa|bbbbb'
    aaaaa
$ echo '    aaaaa   ' | grep -E 'aaaaa\|bbbbb'
$ echo '    aaaaa   ' | grep -G 'bbbbb\|aaaaa'
    aaaaa
$ echo '    aaaaa   ' | grep -E 'bbbbb\|aaaaa'
$ echo '    aaaaa   ' | grep -G 'bbbbb|aaaaa'
$ echo '    aaaaa   ' | grep -E 'bbbbb|aaaaa'
    aaaaa

grep および sed 参照 re_format(7) の両方が明確に述べています:

廃止された(「基本的な」)正規表現は、いくつかの点で異なります。 `| '通常の文字であり、その機能に相当するものはありません。

しかし、「パイプをエスケープする」と、実際に機能が得られるようです。それは確かにそれに匂いがあります。さらに、その球場に最近の破損があるようです regex(3):最近のBRE回帰をカバーするテストを追加する を参照してください。

そして、libcの regex を置き換える作業がいくつかあるようです。

チャールズ・ダフィーが下にコメントするように

一部のツールは非標準の拡張機能を実装しているため、バックスラッシュを使用して、BREコンテキストでEREのみの動作を行うことができます。

私はFreeBSDの非常に優れたドキュメントに慣れています。これは、これが意図されているが文書化されていないのか、それとも破損しているのか、私にはわからないということです。

4
Claus Andersen