正規表現式の (?= ) (?: ) (?! ) の違い

正規表現式の (?=pattern) (?:pattern) (?!pattern) の違いを紹介します。
正規表現の置換で式による結果の違いを比較します。

(?=pattern) の利用

(?=pattern)を利用した正規表現式の結果を確認します。

入力置換パターン置換文字列結果
お店になつみかんが売れ残っていたなつ(?=みかん)もふもふお店にもふもふみかんが売れ残っていた
お店になつすいかが売れ残っていたなつ(?=みかん)もふもふお店になつすいかが売れ残っていた
お店になつみかんが売れ残っていたなつ(?=りんご)もふもふお店になつみかんが売れ残っていた
お店になつみかんが売れ残っていたなつみかんもふもふお店にもふもふが売れ残っていた

「なつ(?=みかん)」を記述した場合「なつみかん」の文字列でマッチします。ただしマッチする部分は「なつ」の文字列の部分となります。「なつすいか」はマッチの対象にはなりません。
「なつみかん」と式を記述した場合は「なつみかん」全体が置換対象となりますが(?=pattern)で記述した場合は、マッチの条件にはなりますが、マッチの範囲には含まれません。

(?:pattern) の利用

(?:pattern)を利用した正規表現式の結果を確認します。

入力置換パターン置換文字列結果
お店になつみかんが売れ残っていたなつ(?:みかん)もふもふお店にもふもふが売れ残っていた
お店になつみかんが売れ残っていたなつ(みかん)もふもふお店にもふもふが売れ残っていた
お店になつみかんが売れ残っていたなつみかんもふもふお店にもふもふが売れ残っていた

「なつ(?:みかん)」を記述した場合、「なつみかん」の文字列でマッチします。マッチする部分も「なつみかん」全体となります。
「なつ(みかん)」と記述した場合でも同様に、「なつみかん」の文字列でマッチします。マッチする部分も「なつみかん」全体となります。
「なつみかん」と記述した場合でも同様に、「なつみかん」の文字列でマッチします。マッチする部分も「なつみかん」全体となります。
上記の3つの式は置換パターンが通常の文字列の場合は同じ結果となります。

続いてキャプチャグループを置換文字列に指定した場合の結果です。

入力置換パターン置換文字列結果
お店になつみかんが売れ残っていたなつ(?:みかん)「$0 "$1"」お店に「なつみかん "$1"」が売れ残っていた
お店になつみかんが売れ残っていたなつ(みかん)「$0 "$1"」お店に「なつみかん "みかん"」が売れ残っていた
お店になつみかんが売れ残っていたなつみかん「$0 "$1"」お店に「なつみかん "$1"」が売れ残っていた

「なつ(?:みかん)」を記述した場合、「なつみかん」の文字列でマッチします。最初のグループ$0にマッチした部分の「なつみかん」が保持されます。
「なつ(みかん)」と記述した場合も、「なつみかん」の文字列でマッチします。最初のグループ$0にはマッチした部分の「なつみかん」全体が保持されます。また、次のグループ$1には()内のパターンにマッチした「みかん」が保持されます。
「なつみかん」と記述した場合も同様に、「なつみかん」の文字列でマッチします。最初のグループ$0にマッチした部分の「なつみかん」が保持されます。
"(?:)"を記述した場合は()内でマッチしたパターンが保持されない動作になる点が異なります。

Splitでの動作の違い

グループ化の違いから、C#でRegEx.splitを利用した場合の動作も異なります。

入力置換パターン結果
みかんとりんごが、お店で売っている、おいしそうです。、おみかんとりんごが
店で売っている、とても
いしそうです。
みかんとりんごが、お店で売っている、おいしそうです。、(お)みかんとりんごが

店で売っている、とても

いしそうです。
みかんとりんごが、お店で売っている、おいしそうです。、(?:お)みかんとりんごが
店で売っている、とても
いしそうです。
みかんとりんごが、お店で売っている、おいしそうです。、(?=お)みかんとりんごが
お店で売っている、とても
おいしそうです。

()でグループ化した場合は、マッチパターンが保持されるため、()内の部分が一つの項目として分割されます。一方 (?:)でグループ化した場合は、マッチパターンが保持されないため、(?:)内の部分は一つの項目として分割されません。(?=)でグループ化した場合は(?=)のパターンはマッチ条件には含まれますがマッチ範囲には含まれないため(?=)内の文字は区切り文字として扱われません。

入力置換パターン結果
広場にみかんとリンゴがたくさん入荷している。みかんは壮観な眺めだね。みかんかんかん、日照りもかんかん。み(かん)*広場に
かん
とリンゴがたくさん入荷している。
かん
は壮観な眺めだね。
かん
、日照りもかんかん。
広場にみかんとリンゴがたくさん入荷している。みかんは壮観な眺めだね。みかんかんかん、日照りもかんかん。み(?:かん)*広場に
とリンゴがたくさん入荷している。
は壮観な眺めだね。
、日照りもかんかん。
広場にみかんとリンゴがたくさん入荷している。みかんは壮観な眺めだね。みかんかんかん、日照りもかんかん。み(?=かん)*広場に
かんとリンゴがたくさん入荷している。
かんは壮観な眺めだね。
かんかんかん、日照りもかんかん。

(?!pattern) の利用

(?!pattern)を利用した正規表現式の結果を確認します。
入力置換パターン置換文字列結果
お店になつみかんが売れ残っていたなつ(?!りんご)もふもふお店にもふもふみかんが売れ残っていた
お店になつりんごが売れ残っていたなつ(?!りんご)もふもふお店になつりんごが売れ残っていた

「なつ(?!りんご)」を記述した場合、「なつりんご」以外の「なつ~」の文字列でマッチします。「なつみかん」は「なつりんご」ではないため、マッチします。マッチの範囲には(?!patttern)は含まれないため「なつ」の部分が「もふもふ」に置換されます。入力が「なつりんご」の場合はマッチせず置換は行われません。

著者
iPentec.com の代表。ハードウェア、サーバー投資、管理などを担当。
Office 365やデータベースの記事なども担当。
掲載日: 2017-11-26
iPentec all rights reserverd.