正規表現メモ
正規表現についてのメモ。確認はPHPのPCRE関数と秀丸エディタ(Ver.8.13)の検索ダイアログで行った。
それ以外の処理系(JavaScript、Javaなど)でも大体同じように使えると思う。
グループ化、非キャプチャグループ
正規表現を "(" と ")" で囲んでグループ化することができる。例えば "ab" が1回以上繰り返しさらに "cd" が1回以上繰り返すという正規表現は "(ab)+(cd)+" となる。
グループ化した部分にマッチする文字列は、グループより後ろの部分で\1,\2,\3,etc...の形式で後方で参照できる。"\"の後ろの数字はグループ化された順番。
正規表現 | 意味 | 文字列 | マッチする部分 |
---|---|---|---|
(ab)+(cd)+ | "ab" が1回以上繰り返し その後に"cd"が1回以上繰り返す。 |
ababcdcdcd | ababacdcdcd |
([a-zA-Z]+) (\d+)-\2\1 |
英字1個以、次に数字1個以上、次にハイフン、 次に前に現れたのと同じ数字1個以上の文字列、 最後に前に出現した英字1個以上の文字列 |
abc123-123abc,xyz789-xyz789 | abc123-123abc |
また、グループ化されたものは\1,\2,\3,etc...の形式で後方で参照できる。
"(?:" と ")" で囲めばグループ化はされるが、後方参照はできなくなる。これを非キャプチャグループと呼ぶ。後方参照が不要な場合はこれを用いてもよい。
非キャプチャグループについては検索して調べると、非キャプチャグループの方が単なるグループより動作が速いと記述も変わらないという記述もある。
OR条件
正規表現で "|" はOR(論理和)を表している。
単純に "ABまたはCD" という意味の正規表現は "AB|CD" でよい。"(AB|CD)" や "((AB)|(CD))" のようにグループ化する必要ない。
しかし、"ABC123" または "ABC456" という風に共通部分があって一部がOR条件の場合は、"ABC(123|456)" のようにグループ化する必要がある。グループ化せずに "ABC123|456" では「"ABC123" または "456"」という意味になる。
後方一致指定、後方不一致指定、前方一致指定、前方不一致指定
- 後方一致指定(肯定先読み)
- 特定のパターンの後にさらに特定のパターンが続くことを表すアンカー。
"(?=<パターン>)" と記述する。 - 後方不一致指定(否定先読み)
- 特定のパターンの後にさらに特定のパターンが続かないことを表すアンカー
"(?!<パターン>)" と記述する。 - 前方一致指定(肯定後読み)
- 特定のパターンの前にさらに特定のパターンが存在することを表すアンカー
"(?<=<パターン>)" と記述する。 - 前方不一致指定(否定後読み)
- 特定のパターンの前にさらに特定のパターンが存在しないことを表すアンカー
"(?<!<パターン>)" と記述する。
正規表現 | 意味 | 文字列 | マッチする部分 |
---|---|---|---|
abc(?=xyz) | 後ろに"xyz"が来る"abc" | abcxyz | abc |
abc(?!xyz) | 後ろに"xyz"以外のパターンが来る"abc" | abcijk | abc |
(?<=abc)xyz | 前に"abc"がある"xyz" | abcxyz | xyz |
(?<!abc)xyz | 前に"abc"以外のパターンがある"xyz" | lmnxyz | xyz |
これらの正規表現はアンカーであり、マッチする文字列には含まれない。アンカーとは位置を指定する正規表現である。
#他のアンカーには "^" や "$" などがある。
また、これらの正規表現の後に正規表現を続けると、AND条件になる。例を示す。
正規表現 | 意味 | 文字列 | マッチする部分 |
---|---|---|---|
abc(?=\w+) | 後ろに単語が続く"abc" | abcdef123 | abc |
abc(?=\w+)[a-z]+ | abcdef123 | abcdef | |
正規表現"abc(?=\d+)[^a-z] | abcdef123 | マッチしない |
\w
"\w" は単語文字の文字クラス。半角の単語文字は英数字とアンダースコア、と思っていたら、処理系やロケールによっては2バイト文字やアルファベット以外の文字も含まれるらしい。
「"\w" と "[:alnum:]" は同じ」という明らかに間違った説明をしているサイトがいくつかあった。何かのドキュメントに「"\w" と "[:alnum:]" は同じ」とあって、それをもとにして書かれた内容なのかなと思う。
秀丸エディタの検索ダイアログとマクロの検索コマンドの違い
秀丸エディタの検索ダイアログで正規表現を使った検索する場合、「正規表現」だけをチェックして実行すると大文字と小文字の違いを無視する。大文字と小文字を区別したい場合は「大文字/小文字の区別」にもチェックを入れる。
一方、マクロでの検索系コマンド(searchdownなど)では "regular" オプションを付ければ大文字と小文字を区別する。
searchdown <検索文字列>, regular;"regular" があれば "casesense" はあってもなくても同じ。"regular" かつ "nocasesense" の場合は大文字と小文字を区別しない。
searchdown <検索文字列>, regular, nocasesense;同じ検索処理なのに検索ダイアログとマクロで使い方の統一性がない。
秀丸エディタの正規表現の注意事項
秀丸エディタの検索・置換・マクロで使う正規表現(以下、「秀丸Regexp」と呼称)と自分がよく使うPHPのPCRE関数や、その他なプログラミング言語の正規表現(以下、「一般Regexp」と呼称)は大体は同じだが、一部独特なところがあるのでメモっておく。
一般Regexpでは前に書いたように "\w" は英数字とアンダースコアを含む文字クラスである。
#それ以外の文字を含む場合もある。
秀丸Regexpでは "\w" は英字とアンダースコアであり、数字を含まない。一般Regexpの "\w" にあたる英数字とアンダースコアからなる文字クラスは "\c" である。
また、一般Regexpでは "\b" は空白文字の文字クラスワード境界のアンカーまたはバックスペース文字であるが、秀丸エディタではバックスペース文字という意味しかない。一般Regexpで "\b" がアンカーがバックスペースかの区別は、角括弧("[]")で囲まれた文字クラスの中ではバックスペース、文字クラスの外ではアンカーである。秀丸エディタには空白文字のもクラスがないが、"\<" と "\>" という英単語の始まり・終わりのアンカーがある。
例として、下記の文字列を考える。
_ab3 C_D4,eF_5
この文字列の単語を検索したい。つまり "_ab3", "C_D4", "eF_5" の3つがマッチするように検索したい。
PHPのPCRE関数であれば以下のコードでできる。難しくはない。
preg_match_all('/\b\w+\b/', "_ab3 C_D4,eF_5", $matches);
秀丸Regexpで同じことをする正規表現は、結構考えてしまった。文字クラス "\b" は使えない。
"\c+" では単語全体だけではなく単語の部分文字列("ab3", "b3", "3", "_D4",etc...) にもマッチする。
"\<\c+\>" では、"\<" と "\>" が「単語」の始まり・終わりではなく「英単語」の始まり・終わりなので、数字を除いた "_ab", "C_D", "eF_" にマッチする。
"(?<=[^\c])\c+(?=[^\c])" とすると行頭の単語以外はマッチする
"(?<=^|[^\c])\c+(?=[^\c])" で行頭の単語を含めてすべての単語にマッチする。期待した動作だ。前方一致指定の中に行頭を表すアンカー "^" が入っているのが若干変な気もするが。
以前の記事の補足説明
以前に秀丸エディタの正規表現について書いた記事で例として挙げた下記の正規表現について、説明不足だったのでここで説明する。
下記の正規表現は "all" や "see" などの「1文字目≠2文字目かつ2文字目=3文字目の3文字の英単語」にマッチする。
\<([a-z])((?!\1)[a-z])\2\>
・先頭の "\<" と末尾の "\>" はそれぞれ単語の始まり、終わりを示す。これらがあるため、例えば3文字の単語にはマッチするが4文字以上の単語の一部分の3文字("tall" や "seem" など)にはマッチしない。
・"([a-z])" はアルファベット小文字の1文字。後方参照のためグループ化してある。
・"((?!\1)[a-z])" は後方不一致指定(否定先読み)を使っている。"\1" は前のグループ、つまりこの部分の前にあるアルファベット小文字1文字である。"(?!\1)" はその1文字ではないものが後にあるというアンカー。"[a-z]" はアルファベット小文字1文字であり、後方不一致指定の後にパターンがある場合は、後方不一致指定とそのパターンがAND条件となる。よって、"(?!\1)[a-z]" は「前のアルファベット小文字1文字とは異なるアルファベット小文字1文字」となる。アンカーである後方不一致指定だけではなく後に "[a-z]" があるため1文字とマッチし、後方参照のためにグループ化されている。
・"\2" は前のグループ、"(?!\1)[a-z]" にマッチしたアルファベット小文字1文字である。
・以上から、全体としては「1文字目と2文字が異なり、2文字目と3文字が同じである3文字のアルファベット小文字の単語」にマッチする。
参考文献:秀丸エディタヘルプ
参考サイト:
正規表現言語 - クイック リファレンス
Windowsユーザーに教えるLinuxの常識(6):使うほどに良さが分かる正規表現 (2/2) - @IT
正規表現(肯定先読み、否定先読み、肯定戻り読み、否定戻り読み) - satosystemsの日記:
正規表現の先読み・後読みを極める! - あらびき日記
« SQLインジェクション その4 | Main | SQLインジェクション その5 »
「Java」カテゴリの記事
- 正規表現メモ(2013.10.07)
- Androidアプリ開発メモ068:Tweenアニメーション(2012.11.18)
- Androidアプリ開発メモ067:NDKのサンプルを動かしてみた(2012.09.10)
- JNI その2:ネイティブコードからJavaメソッドを呼び出す(2012.08.29)
- JNI その1:Javaからネイティブコードを呼び出す(2012.08.26)
「プログラミング、技術情報」カテゴリの記事
- PHPStorm 2018.1.7 に更新(2018.12.09)
- 技術メモをQiitaに移行(2016.01.24)
- 正規表現メモ:ものぐさ(最小)マッチング(2015.11.29)
- BASE64にエンコード/デコードするバッチファイル(2015.11.23)
- Windows7の検索ボックスの検索条件指定(フォルダの除外など)(2015.08.16)
「PHP」カテゴリの記事
- PHPStorm 2018.1.7 に更新(2018.12.09)
- PHPメモ051:includeとrequireの使い分け(2015.06.19)
- CakePHPのインストール(2015.06.14)
- PHPからPDOでPostgreSQLに接続する(2015.06.09)
- PHPでメールを送信したら一部のOutlookで受信したメールでヘッダがおかしくなった(2015.05.31)
「JavaScript」カテゴリの記事
- JSONのオブジェクトは順序性を持たない(2015.05.08)
- HTML全体からjQueryオブジェクトを作成、find()とfilter()の違い(2014.10.19)
- jQueryのセレクタについてメモ(2014.10.10)
- 選択リストを拡張するSelect2(2014.09.28)
- JavaScriptの正規表現で前方一致(後読み)が使えない(2014.06.16)
「秀丸エディタ」カテゴリの記事
- 秀丸エディタのTSV・CSVモード(2014.10.07)
- 秀丸エディタマクロの検索・置換系命令のinselectオプション(2014.09.16)
- 秀丸エディタのマクロにおける配列(2013.12.24)
- 正規表現メモ(2013.10.07)
- 連続した日付、時間の文字列を作る秀丸マクロのサブルーチン(2013.10.03)
The comments to this entry are closed.
Comments