My Photo

« SQLインジェクション その4 | Main | SQLインジェクション その5 »

October 07, 2013

正規表現メモ

正規表現についてのメモ。確認は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 マッチしない
2014/06/16追記:JavaScriptの正規表現では前方一致指定と前方不一致指定が使えない。

\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」カテゴリの記事

プログラミング、技術情報」カテゴリの記事

PHP」カテゴリの記事

JavaScript」カテゴリの記事

秀丸エディタ」カテゴリの記事

Comments

The comments to this entry are closed.

TrackBack


Listed below are links to weblogs that reference 正規表現メモ:

« SQLインジェクション その4 | Main | SQLインジェクション その5 »

June 2021
Sun Mon Tue Wed Thu Fri Sat
    1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30      
無料ブログはココログ

日本blog村

  • にほんブログ村 IT技術ブログへ
  • にほんブログ村 アニメブログへ
  • にほんブログ村 サッカーブログ アルビレックス新潟へ

好きな音楽家

メモ

XI-Prof