次の正規表現の例は、「正規表現をマスターする」の22ページから得られます。
'\<([a-z]+) +\1\>'
私は正規表現に最初に触れましたが、本ではこれを明示的に言及していませんが、標準正規表現記号ではないという印象を\<
受けました\>
。検索してみると、grep
正規表現構文のGNU拡張であるようです。たぶん具体的ではないかもしれませんgrep
。わかりません。
いずれにせよ、このシンボルが何を意味するのか分かりません。。この質問の残りの部分では、異なる定義または定義の試みを引用します。そのうちのいくつかは明らかに間違っている、理解できない、または少なくとも不完全です。誰かが私に正確な定義を伝えることができれば幸いです。最後の引用は次のとおりです。https://www.grymoire.com/Unix/Regular.html#uh-9、正解である可能性が高いです。しかし、公式文書には異なる方法が記載されています。
本は言う
(奇妙に思えるかもしれない)メタシーケンス
\<
と\>
[...]を使うことができます。^
それぞれの$
単語の始まりと終わりの位置を一致させるとの単語ベースのバージョンと考えることができます。
それから後で
「単語の始まり」は、単に一連の英数字が始まる場所である。 「単語の終わり」は、これらのシーケンスが終わる場所です。次のページの図 1-2 は、これらの位置が示された例の行を示しています。
図1-2が役に立ちます。
にも「記録」されています。GNU findutils マニュアル これは次のように言います。
‘\<’ matches the beginning of a word
‘\>’ matches the end of a word
そこにもGNU grep マニュアルそれは言う:
'\<'
Match the empty string at the beginning of word.
'\>'
Match the empty string at the end of word.
この説明が何を意味するのかわかりません。したがって、GNUのマニュアルから抜粋したもののどれも役に立ちません。
最初にこの質問を書いたときに、「正規表現の習得」セクションを注意深く読んでいないこと、図1-2も見ていない、その記号が「単語I」の前後に空白文字があるという意味だと思いました。今これが間違っていることに気づきなさい。しかし、本の説明でさえ不正確または不完全です。
次の 2 つの例を考えてみましょう。
grep --color -E -i '\<([a-z]+) +\1\>' <<< 'wibble someword someword-something else wibble'
これは「someword someword」と一致します。
grep --color -E -i '\<([a-z]+) +\1\>' <<< 'wibble someword someword_something else wibble'
ここに一致するものはありません。
この本では、「単語の終わり」が英数字のシーケンスが終わる場所であると言うので、これについては説明しません。 GNUマニュアルから抜粋した内容も同様です。
可能な説明は以下に提供される。https://www.grymoire.com/Unix/Regular.html#uh-9(ランダム検索で見つけました)内容は以下の通りです。
単語の検索は一見するほど簡単ではありません。文字列「the」は「other」という単語と一致します。文字の前後にスペースを追加し、「the」という正規表現を使用できます。ただし、これは行の先頭または末尾の単語と一致しません。そして、単語の後に句読点がある場合は一致しません。
"t"の前の文字は改行文字であるか、文字、数字、下線以外の文字でなければなりません。 「e」の後の文字は、数字、文字、アンダースコア以外の文字でなければならず、行終端文字でもあります。
著者がここでこれを得ているかどうかはわかりませんが、それが真であると仮定すると、私が見ている動作を説明できます。しかし、まだかなりカジュアルに見えます。-
句読点ではありません。なぜ単語の一部として含めることはできませんか?あるいは、言い換えれば、ハイフンは単語の終わりと一致しますが、下線が一致しないのはなぜですか?実際、自然言語では、下線よりもハイフンがより一般的です。プログラミング言語では下線を使用できます。
これが正しい場合、GNU文書は実際にそれを正確に文書化する必要があります。これを理解したら、バグレポートを送信できますか?
理想的には、この機能をカスタマイズできます。しかし、多分それはあまりにも多くを要求するかもしれません。
GNUコードから抜粋したこのgrep
内容はwww.grymoire.com正しいかもしれません。関連コードはinit_word_char
"lib/regcomp.c"の関数にあり、次のようになります。
general_case:
for (; i < BITSET_WORDS; ++i)
for (j = 0; j < BITSET_WORD_BITS; ++j, ++ch)
if (isalnum (ch) || ch == '_')
dfa->word_char[i] |= (bitset_word_t) 1 << j;
ここで重要な行はもちろん、ファイルの983行です。
if (isalnum (ch) || ch == '_')
つまり、文字は英数字または下線です。
もちろん、私はこのコードが何を意味するのかよく理解していません。
答え1
正規表現に関連する「単語」の正式で正確な定義を仮定しているように見えますが、意味は実際には実装によって異なります。
実際に引用した本の「正規表現命名法」、「味」の段落で
両方のプログラムが⌈\<···\>⌋をサポートしていても、自分が行うことに同意せず、それを単語と見なすことはできません。
この概念の可変性を示す例として、Wikipediaの正規表現ページ[:word:]
[:word:]
アンダースコアを含むがシンボルに関連付けられた脚注を含むように非標準の文字クラスを定義します。Emacs Lisp マニュアルここで、文字クラスは「単語構文を持つすべての文字」と一致すると言われ、さらに連結されます。構文クラス表それいいえ「単語コンポーネント」にアンダースコアを表示します(「シンボルコンポーネント」にリストされています - 「変数とコマンド名と単語コンポーネントに使用される追加の文字」として定義されています)。
この観点から見ると、上記の記述は明らかに不正確です。
「単語の始まり」は、単に一連の英数字が始まる場所です。
定義ではなく単純化と見なすことができます。
「単語の先頭に一致」や「単語の先頭に位置一致」などの表現もあまり形式的には聞こえない。空の文字列を含むバージョンはあまり明確ではありませんが、より正確です。正式に定義された概念1。
ほとんど、
'\<' は
単語の先頭の空の文字列と一致します。
\<
文字列に単語形成文字(GNU grep定義による[:alnum:]
文字クラスの1つまたはa _
)が含まれていて、単語形成文字の直前にない場合にのみ文字列が一致することを示します。
その後、例のパターンは、\<([a-z]+) +\1\>
「1つ以上の小文字のアルファベット文字シーケンス(ロケールの「a」と「z」の間にソートされています)」で読み取ることができます。その前に小文字のアルファベット文字が続き、最後の文字の後に単語を作成する文字はありません。
1 正規表現コンテキストで長さ0の文字列。正しいかもしれません、本当にすべて行には、空行を含む対応する項目が含まれます。 ~になる接続操作のID要素、リテラル文字の前後に一致することができます。たとえば、X*
で一致するもの、 で一致する空のパターンgrep 'oX*o' <<<foo
、 で一致するもの、 ; で一致するものです。''
grep '' <<<''
echo "" | grep '^$'
\<
grep '\<' <<<'a'
答え2
その部分GNU grepマニュアルから説明する:
\<
単語の先頭の空の文字列と一致します。
\>
単語の末尾の空の文字列と一致します。
「単語」の始まりと終わりに一致するため、文字列と一致\<bar
するfoo bar
か、単に一致しますbar
が、文字列と一致しませんfoobar
。一致は空の文字列と一致すると説明されています。一致する場合、一致は \<bar
egfoo bar
ではbar
なく、<space>bar
一致\<
する文字列(egに関連付けられているgrep -o
)に文字が追加されないためです。
標準ではありません。
\w
の同義語である単語コンポーネントを一致させます[_[:alnum:]]
。
マニュアルには次の内容が記載されています。小さな文字に注意してください。単語文字には英数字(現在のロケールで意味するもの)が含まれます。下線を引く。したがって、2番目の試みで探しているものと実際には一致しませんsomeword_something
。someword\>
grep
はい、これは多くのプログラミング言語では、識別子名に英数字と下線を付けることができるためです。ハイフンではなく減算演算子です。
もちろん、CとJavascriptでは$
識別子名にも有効であり、識別子名は数字で始めることはできませんが、すべてを持つことはできません。