part31 - 文字列 の 否定
正規表現 否定 文字列
いろいろな環境の中には、先読みの否定である (?! ) が
使えない環境があります。 このような環境では、
「ABC」 という文字列を含まない
というような、文字列の否定をする正規表現を作るのは
とても難しい作業になります
※ (?! ) が使える環境での作り方は こちら 。
では、例として、
以下のようなテキストにマッチする正規表現を考えてみましょう★
・ テキストの先頭が AA から始まる
・ テキストの末尾が AA で終わる
・ 先頭の AA と、末尾の AA との間に挟まれた文字列の中には
AA が存在しない
ちなみに、
"AAAAA" というテキストの場合、中に挟まれた文字列が
A の1文字だけなので、マッチするものとします
▽ マッチさせたいテキストの図
このような場合、
まず、以下のように正規表現に使えそうなパーツを書き出します
^AA ・・・ テキストの先頭にある AA にマッチする表現
AA$ ・・・ テキストの末尾にある AA にマッチする表現
A[^A] ・・・ ”A 1文字” の後ろに ”A以外の1文字” が
あれば、この2文字にマッチする表現
[^A] ・・・ ”A以外の1文字” にマッチする表現
(重要) A[^A] は 2文字 にマッチするということを忘れないで下さい
ちなみに、 A[^A] と [^A] は以下のような関係になっています
・ ある文字が A 以外ならば、 [^A] にマッチする
・ ある文字が A であり、次の文字が A 以外ならば、
この2文字が A[^A] にマッチする
・ ある文字が AA の A ならば、A[^A] にも [^A] にもマッチしない
これを図にすると下のようになります
▽ A[^A] と [^A] の関係図
この図を見ると、ある文字にマッチさせるには、
A[^A] または [^A] にマッチさせればいいことが分かります
つまり、以下のようになります
(A[^A]|[^A])
そして、これを繰り返せば AA を含まない文字列となります
(A[^A]|[^A])*
最後に、
テキストの先頭と末尾の AA にマッチする表現を付け足し、
以下のようにすれば完成・・のはずですね
^AA(A[^A]|[^A])*AA$
では、試しに動かしてみましょう!
※ テキストエディタの OtbEdit では ^ と $ が行頭、行末にも
マッチするので、1行につき1つのテキストをテストします
▽ 「 ^AA(A[^A]|[^A])*AA$ 」 を動かした図
図を見てみると、1、3、5、9、11行目は期待通りにマッチ
していますが、 2、6、10行目がマッチしていません
何故、この3行がマッチしないのかというと、
テキスト末尾にある AA のせいで、A[^A] がマッチしないのです
▽ 「 AA000AAA 」 の図
しかも、 A[^A] は 2文字 にマッチする表現なので、
1文字の A にはマッチ出来ません!
このように、文字列の否定表現では、
テキストの先頭、末尾の部分と競合して予期しない動作になる
ことが非常に多いので、必ずチェックしましょう!
では、これを直す作業を始めましょう
こういう誤作動を直す方法はケースバイケースなので
毎回違ってきますが、今回は下の図のように修正すればOKです
▽ 誤作動を直す図
A[^A] でマッチ出来ないなら AA$ にマッチさせよう、
という発想です
では、 AA$ が AAA にもマッチするように修正します
AAA?$
A? を付けたので AA にも AAA にもマッチしますね!
これを適用した正規表現がこちらです
^AA(A[^A]|[^A])*AAA?$
では、改めてテストしてみましょう
▽ 「 ^AA(A[^A]|[^A])*AAA?$ 」 を動かした図
2、 6、10行目もマッチしてますね! これで完成です★
今回は2文字の文字列の否定でしたが、否定する文字数が
多くなるととても複雑になります
その場合は以下のような対策を検討しましょう
・ (?! ) を使えないかを確認しましょう
(?! ) を使えれば記述がとてもシンプルになります
・ 否定の正規表現を使わずに済む方法がないかを確認しましょう
プログラムでは ”肯定の正規表現がマッチしたらfalseにする” 等
・ 下記の自動生成 javascript で作成する
また、今回のような正規表現を作るには 状態機械 や
状態遷移図 、 オートマトン などの知識を身に付けると
取りこぼしの無い正確な正規表現が作れるように
なる・・のかも知れませんがよく分かりません
興味がある方は調べてみて下さい (^^;)
○ (?! ) に関連するページ
part29 - 先読み 否定 (?! )
part11 - いろいろな繰り返し (6)
○ 参考になるサイト
秀丸Q&A - 第IV部~テキスト編集を極める!!正規表現について
http://homepage2.nifty.com/jr-kun/hidemaru_qa/4_regulr.html
”[2-2] 「文字列の否定」について” の項目がとても参考になります
※ 秀丸では (?! ) が使えます
Perl正規表現雑技
http://www.din.or.jp/~ohzaki/regex.htm#WithoutXY
”xy を含まないものにマッチする正規表現” と
”xyz を含まないものにマッチする正規表現” が参考になります
正規表現メモ
http://www.kt.rim.or.jp/~kbk/regex/regex.html
”ある文字列を含まない正規表現” の項目に文字列の否定表現を
自動生成する javascript があります
( ”AA” の否定は出来ないようです )
教えてgoo - 文字列を含まないという正規表現は?
http://oshiete1.goo.ne.jp/qa4522181.html
プログラミングに関して有益なレスが付いています
ReplaceStrTool
http://1st.geocities.jp/neeetest/jane.html
( ) が何重にもなる複雑な正規表現を読みやすくするツールです
正規表現をコピーし、ツールの ”貼り付け” ボタンを押しましょう
フォームをダブルクリックするとフォームが最大化します
▽ ReplaceStrTool の階層表示機能の図