この記事は昔正規表現について調べた時のメモをqiitaにあげ直したものです。前提としてmac, linuxを使っていることが前提になっている内容が一部あります。
正規表現とは
正規表現とは、特定のルールを満たす文字列の集合を一つの文字列で表現するための方法。
例えば、「英小文字の一回以上の繰り返し」はpythonの正規表現では"``[a-z]+``"
で表現することができ、数式で表現するなら、
{“a”, “abc”, “hogehoge”} ⊂ "[a-z]+” = { x | xは英小文字の一回以上の繰り返し}
みたいな関係が成り立ちます。
------ Pythonの公式ページの説明
正規表現 regular expressions (REs や regexes または regex patterns と呼ばれます) は本質的に小さく、Python 内部に埋め込まれた高度に特化したプログラミング言語でre
モジュールから利用可能です。この小さな言語を利用することで、マッチさせたい文字列に適合するような文字列の集合を指定することができます
POSIX基本/拡張正規表現とは
POSIXとは
---------- Wikipedia
POSIX(ポシックス、ポジックス、英: Portable operating system interface)は、各種UNIXを始めとする異なるオペレーティングシステム (OS) 実装に共通のアプリケーションプログラミングインタフェース (API) を定め、移植性の高いアプリケーションソフトウェアの開発を容易にすることを目的としてIEEEが策定したAPI規格である。POSIXという名前はリチャード・ストールマンがIEEEに提案したものである[1]。末尾の「X」はUNIX互換OSに「X」の字がつく名前が多いことからつけられた。ISO/IEC JTC 1/SC 22でISO/IEC 9945として国際規格になっている。
POSIX基本正規表現(BRE)とは
----------- Wikipedia
この文法では、ほとんどの文字はリテラル(機能を意味せず書かれたそのまま)に扱われる。つまり、ある文字はその文字にのみマッチする。例えば、正規表現「a
」は文字「a
」にマッチし、正規表現「(bc
」は文字列「(bc
」にマッチするなど。例外はメタ文字と呼ばれる。
メタ文字とは、リテラルとしての意味とは異なる意味を持つ文字のことです。BREではメタ文字の機能を呼び出すためにバックスラッシュを用いる。
POSIX拡張正規表現 (ERE)とは
------- Regular-Expresions.info
Extended Regular ExpressionsまたはEREフレーバーは、UNIXのegrepコマンドで使用されるものと同様のフレーバーを標準化しています。最新の正規表現フレーバーのほとんどはEREフレーバーの拡張です。今日の標準では、**POSIX EREフレーバーはExtendedとはいえかなりbasicなものです。**POSIX標準は1986年に定義され、それ以来、正規表現は長い道のりを歩んできました。
要するに
POSIX準拠の正規表現を覚えていれば、ほとんどのUNIX系OSのコマンドで共通の正規表現が使える。
大抵のプログラミング言語もPOSIX正規表現と同等の表現が使える。
コマンド例 | |
---|---|
BRE | sed, vi, more, grep |
ERE | egrep, awk, bash |
正規表現の細かい仕様は言語ごとにに異なるhttps://gist.github.com/CMCDragonkai/6c933f4a7d713ef712145c5eb94a1816
EREの仕様の確認方法
ターミナルを起動して以下を実行
$ man 7 re_format
使い方メモ
-
h
キーを押す -
q
キーを押す -
/\*
を入力してエンター
EREの仕様(一部)
メタ文字 | 意味 |
---|---|
* |
後ろに* が付いている正規表現はその正規表現の0回以上の繰り返しにマッチする$${abc, abcababab, abcab} \subset (abc)(ab)*$$ |
+ |
後ろに+ が付いている正規表現はその正規表現の1回以上の繰り返しにマッチする$${abcababab, abcab} \subset (abc)(ab)+$$ |
? |
後ろに? が付いている正規表現はその正規表現の0から1回の繰り返しにマッチする$${hog, hoge} = hoge?$$ |
{ |
繰り返しは{ の後に符号なし10進整数が続き、場合によっては, と別の符号なし10進整数が続き、最後に} で閉じられる.$${hoghog, hoghoge, hogehog, hogehoge} = (hoge?){2}$$ $${aa, aaa, aaaa} = a{2, 4}$$ |
} |
同上 |
( |
() で閉じられた部分は正規表現に対するマッチにマッチする.$${abcababab, abcab} \subset (abc)(ab)+$$ |
) |
同上 |
. |
. は任意の一文字にマッチする.$${hoge, hogeasdkoasdk} \subset hoge.*$$ |
^ |
^ は行のはじめのnull文字にマッチする.例えば、 “^bb.” にマッチする文字列を “”” aabbaa bbccbb “”” から検索すると、”bbc”のみがマッチする. |
$ |
$ は行の終わりのnull文字にマッチする.例えば、 “.bb$” にマッチする文字列を “”” aabbaa bbccbb “”” から検索すると、”cbb”のみがマッチする. |
\ |
エスケープシーケンス |
[ |
[] で閉じられた部分にリストされた任意の文字にマッチする. ただし、文字のリストが^ で始まる場合はリストされた^ 以外の任意の文字にマッチする. ただし、リスト内の2文字が- で区切られている場合、2つの間の全範囲の文字の省略形として扱われる. (両端も含まれる)$${a, b, c, d, e, z} \subset [a-z]$$ $${d, e, f, g, z} \subset [^abc]$$ |
] |
同上 |
\ 数字※拡張されたEREでのみ使える |
n番目に記した包括指定子でマッチした文字列にマッチする. $${abc123abc, hoge123hoge} \subset ([a-z]*)123\1$$ |
pythonで正規表現を使う際に注意しないといけないこと
注意しないといけないこと
- パターンと検索文字列の文字コードは一致させること
- 使える文字コード一覧
- Unicode文字列:
str
- 8ビット文字列:
bytes
- Unicode文字列:
- 使える文字コード一覧
- バックスラッシュ感染症を起こさないようにパターン文字列にraw string記法を行う
- EREでは正規表現
$
(^
)は行末(行の先端)を表すけどpythonでは文字列の終端(先端)を表す -
\s
を使えば改行とマッチできる
バックスラッシュ感染症とは
正規表現パターンはキャラクタリテラルと特殊文字で構成される. 特殊文字の一つにエスケープシーケンス\
があり、\特殊文字
で特殊文字の効果を消した特殊文字自体を表現する際に使用される. 従って、正規表現"``\\w``"
は正規表現エンジンにより"``\w``"
に置き換えられる(ここでの\
はエスケープシーケンスではなく文字そのもの). しかし、pythonのパーサーもまた文字列中の\
はエスケープシーケンスとして扱うため、正規表現エンジンに"\\w"
を渡す前にエスケープシーケンスが評価されてしまう. つまり、"\w"
が正規表現エンジンに渡されてしまうため、結果的に[a-zA-Z0-9_]
を正規表現エンジンに渡した時と同じ結果が得られることになる. これはプログラマの意図とは異なるかもしれない. このような現象をバックスラッシュ感染症という.
バックスラッシュ感染症を回避する方法としては、re.compileの引数にする正規表現パターン文字列にraw string記法を用いるのが一般的. 上の例で言えば、re.comple(r"\w")とすれば良い.
蛇足: バックスラッシュ感染症が起きないように改善しない理由
-----Python公式ページの説明
正規表現は文字列としてre.compile()
に渡されます。正規表現は文字列として扱われますが、それは正規表現が Python 言語のコアシステムに含まれないためです、そのため正規表現を表わす特殊な構文はありません。 (正規表現を全く必要としないアプリケーションも存在します、そのためそれらを含めて言語仕様を無駄に大きくする必要はありません)
pythonの正規表現パターンを調べる方法
pythonの正規表現を調べるツールを使うと便利かもしれません.
$curl https://raw.githubusercontent.com/python/cpython/3.6/Tools/demo/redemo.py > ~/Desktop/redemo.py
$python ~/Desktop/redemo.py
関数とインスタンスメソッド、どっちを使うべき?
------- Python公式ページ
パターンオブジェクトを作ってそのメソッドを呼び出す、とする必要は必ずしもありません。re
モジュールはトップレベルの関数としてmatch()
,search()
,findall()
,sub()
などを用意しています。これら関数は、対応するメソッドの最初の引数に RE が追加されただけで後は同じで、None
か Match オブジェクト インスタンスを返すのも同じです
内部的には、re.compileは単にあなたのためにパターンオブジェクトを生成し、対応するメソッドを呼び出すだけのことです。とともに、将来の呼び出しで同じ RE のパースが何度も何度も必要とならないよう、コンパイル済みオブジェクトはキャッシュされます。