Python3 – 正規表現 – 選択演算子’|’とfindall/finditerの注意点

findall()finditer()のパターン文字列で選択演算子'|'を用いるとき、選択文字列の順序によって結果が変わってくる点に注意が必要。

たとえばreモジュール関数の場合、以下の例のようになる。

'aa|aaa'とした場合以下の順番でマッチしていく。

  • "a,|aa|,|aa|a,aaaa,aaaaa"
  • "a,|aa|,|aa|a,|aa|aa,aaaaa"
  • "a,|aa|,|aa|a,|aa|aa|,aaaaa"
  • "a,|aa|,|aa|a,|aa|aa|,|aa|aaa"
  • "a,|aa|,|aa|a,|aa|aa|,|aa|aa|a"

'aaa|aa'とした場合は以下の順番でマッチしていく

  • "a,|aa|,aaa,aaaa,aaaaa"
  • "a,|aa|,|aaa|,aaaa,aaaaa"
  • "a,|aa|,|aaa|,|aaa|a,aaaaa"
  • "a,|aa|,|aaa|,|aaa|a,aaaaa"
  • "a,|aa|,|aaa|,|aaa|a,|aaa|aa"
  • "a,|aa|,|aaa|,|aaa|a,|aaa|aa|"

つまり、各マッチングの段階で選択演算子'|'の左側からマッチする部分をまず探し、該当しなければ演算子の右へと判定パターンを変えていく。

このため、演算子の左のパターンが右のパターンより短いと、先にそちらがマッチングされるので右の長いパターンがマッチしなくなることがある。

この動作は、正規表現オブジェクトのメソッドについても同じ。

 

 

Python3 – 正規表現 – エスケープとraw文字列

エスケープの問題

正規表現ではいくつかの文字がパターンとしての特別の意味を持つが、その文字そのものをマッチングの対象としたいときにはバックスラッシュ(\)でエスケープする。

さらに検索対象の文字列にバックスラッシュが含まれている場合には、バックスラッシュ自身をエスケープしなければならない(\\)。このようなケースは、ファイルパスの区切りにバックスラッシュが使われている場合やLATexの\begin~\endなど多くある。

下の例は”\bigin”という文字列を検索する場合。

  • 検索される側の文字列のバックスラッシュをエスケープしなければならない(3行目)
    • その文字列をprintしてみると意図した内容になっている(4行目と9行目)
  • 次にパターン文字の方で、”\begin”とそのまま試してみるとヒットしない(5行目と10行目)
    • これは最初の”\b”がPythonのエスケープシーケンス(バックスペース)として解釈されたため
  • そこでバックスラッシュをエスケープしてもヒットしない(6行目と11行目)
    • Pythonでは文字としてのバックスラッシュとして解釈されるが、今度は正規表現として解釈したとき単独の特殊文字としての’\’となるため
  • 2つのバックスラッシュそれぞれをエスケープするようにしてやっとヒットさせることができる(7行目と11行目)

raw文字列

Pythonでは、バックスラッシュを単なる文字として解釈するためのraw文字列が組み込まれていて、文字列リテラルの前に’r’か’R’を付けるだけでよい。”””で囲まれた複数行文字列でも同じ。

また、Python3で文字列変数の文字列をraw文字列に変換するには、repr()関数を使う。ただしその結果はシングルクォートで囲まれているため、それを取り除かなくてはいけない。

また複数行文字列の場合は、リテラルでのr指定と変数へのrepr()適用で結果が異なってくる。

 

Python3 – 正規表現 – MatchObject

概要

search()などのreモジュール関数正規表現オブジェクトメソッドが実行の結果マッチした場合に、MatchObjectオブジェクトが返される。以下、MatchObjectのオブジェクトをmatchオブジェクトと表現する。matchオブジェクトは常にブール値Trueを持ち、matchオブジェクトそのものを判定式に使ってマッチしたかどうかの判定ができる。

matchオブジェクトの文字列表現には、(最初に)ヒットした場所の範囲と、マッチした内容が含まれている。

正規表現・文字列情報

re

match.re

matchを生成した正規表現オブジェクト。

string

match.string

matchを生成したsearch()match()へ渡された文字列。

グループ指定しない場合のマッチング結果

group()、start()、end()、span()

match.group()match.start()match.end()match.span()

group()はマッチした部分文字列、start()とend()はマッチした部分文字列の開始位置と終了位置、span()は(開始位置, 終了位置)のタプル。

グループ指定した場合のマッチング結果

group()

match.group()match.group([group1, ...])

引数がない場合は、マッチしたもの全てが返される。引数がある場合はグループを指定(数字のほかグループ名でも可)。

groups()

match.groups()

マッチしたグループを要素とするタプルとする。

lastindex

match.lastindex

複数グループの最終インデックス。

 

 

Python3 – 正規表現 – モジュール定数

ここでは正規表現の操作に使われるモジュール定数を整理する。

re.A/re. ASCII
\b\B\d\D\s\S\w\Wにおいて、ASCII文字のみでマッチングを行う。Unicodeパターンでのみ意味があり、バイト列パターンでは無視される。
re.I/re.IGNORECASE
英大文字・小文字を区別せずにマッチングを行う。{A-Z]のような表現で小文字ともマッチする。現在のロケールに影響を受けず、Unicode文字に対しても動作する。
re.L/re.LOCALE
\b\B\s\S\w\Wにおいて、現在のロケールに従ったマッチングを行う。バイト列でのみ意味を持つ。非推奨。
re.M/re.MULTILINE
デフォルトでは'^'は文字列全体の先頭に、'$'は文字列全体の末尾にのみマッチするが、このフラグにより、'^'は文字列の先頭と各行の先頭(各改行の直後)、'$'は文字列の末尾と各行の末尾(各改行のの直前)とマッチする。
re.S/re.DOTALL
デフォルトでは'.'は改行にマッチしないが、このフラグにより'.'を改行を含む任意の文字とマッチさせる。
re.X/re.VERBOSE
このフラグにより、パターン文字列内に改行・インデントを入れたりコメントを入れるなど、より読みやすい正規表現を書くことができる。コメントには'#'を使う。

Python3 – 正規表現 – 正規表現オブジェクトメソッド

概要

reモジュールではre.RegexObjectクラスが定義されている。パターン文字列をコンパイルするとRegexObjectのオブジェクトが生成され、そのパターンはそのプロパティとして保持される。このクラスの各メソッドで、パターンを任意のテキストに適用する。

reモジュール関数を使う場合は実行のたびにパターン文字列とフラグを指定し、その都度コンパイルされる。一方、正規表現オブジェクトのメソッドを使う場合は、一度パターンをコンパイルしておけば、その後の操作でコンパイルのオーバーヘッドが生じない。フラグはコンパイル時に指定する。

パターンの検索

search()

regex.search(string,[ pos[, endpos]])

re.search()関数と同じ機能で、stringの任意の位置で、最初にregexにマッチした時にMatchObjectのオブジェクトを返す。マッチしなければNoneを返す。

posは検索開始位置で先頭が0。デフォルト値は0で先頭から検索する。

endposは検索範囲の終了位置で、endpos-1文字目までが検索範囲となる。デフォルトでは文字列の最後まで検索する。

match()

regex.match(string[, pos[, endpos]])

re.match()関数と同じ機能で、regexstringの先頭でマッチするときだけMatchObjectオブジェクトを返す。posendposregex.search()と同じ意味。

fullmatch()

regex.fullmatch(string[, pos[, endpos]])

re.fullmatch()関数と同じ機能で、regexstring全体にマッチするときだけMatchObjectオブジェクトを返す。posendposregex.search()と同じ意味。

findall()

regex.findall(string[, pos[, endpos]])

re.findall()関数と同じ機能でregexにマッチする部分列のリストを返す。posendposregex.search()と同じ意味。

finditer()

regex.finditer(string[, pos[, endpos]])

re.finditer()関数と同じ機能で、regexにマッチする部分列のイテレータを返す。posendpossearch()と同じ意味。

分割

split()

regex.split(string, maxsplit=0)

re.split()関数と同じ機能で、regexにマッチする部分列でstringを切り分ける。posendpossearch()と同じ意味。

置換

sub()

regex.sub(repl, string, count=0)

re.sub()関数と同じ機能でstring中のregexにマッチする部分をreplで置き換える。replには文字列を返す関数も指定可能。posendpossearch()と同じ意味。

subn()

regex.subn(repl, string, count=0)

re.subn()関数と同じ機能で、置換後にタプルで(置換後の文字列, 置換数)を返す。posendpossearch()と同じ意味。

 

Python3 – 正規表現 – モジュール関数

概要

reモジュールの関数は、パターンと文字列を直接指定してマッチングなどの操作を行う。

引数の中のflagsについては、reモジュールで定義された定数を指定する。複数のflagsを指定する場合は、ビットごとのOR('|'演算子)を使って組み合わせる。

パターンは実行に先立ってコンパイルされるので、同じパターンを複数回用いる場合には、re.compile()関数でパターンをコンパイルし、コンパイルされたRegexObjectオブジェクトのメソッドを用いる方がよい。

正規表現のコンパイル

compile()

re.compile(pattern, flags=0)

正規表現パターンを正規表現オブジェクトにコンパイルする。正規表現オブジェクトのメソッド群で、以下のモジュール関数と同等の操作を行うことができる。

以下のモジュール関数を使う場合はflagsを関数ごとに指定するが、正規表現オブジェクトを使う場合は、compile()関数の引数でflagsを指定する。

パターンの検索

re.search(pattern, string, flags=0)

stringの任意の位置で、最初にpatternにマッチした時にMatchObjectのオブジェクトを返す。マッチしなければNoneを返す。

match()

re.match(pattern, string, flags=0)

stringの先頭でpatternにマッチすればMatchObjectのオブジェクトを返す。マッチしなければNoneを返す。stringの途中ではマッチしない。

fullmatch()

re.fullmatch(pattern, string, flags=0)

patternstring全体にマッチしたときだけMatcObjectのオブジェクトを返し、それ以外はNoneを返す。

findall()

re.findall(pattern, string, flags=0)

string中でpatternにマッチする全ての部分文字列を要素とするリストを返す。マッチする部分がなければ空のリスト([])を返す。先頭からマッチした部分を取り除きながらサーチしていく。

finditer()

re.finditer(pattern, string, flags=0)

string中でpatternにマッチした結果のMatchObjectオブジェクトのイテレータを返す。マッチする部分がなければ空のイテレータを返す。先頭からマッチした部分を取り除きながらサーチしていく。

分割

split()

re.split(pattern, string, maxsplit=0, flags=0)

stringをすべてのpatternにマッチする部分で分割し、それらを要素とするリストを返す。patternにマッチする部分は除かれる。マッチする部分がなければ、stringを1つの要素とするリストが返される。

maxsplitに1以上の数nを指定すると、先頭から最大n個の分割が発生し、残りはリストの最後の要素となる。

patternが先頭の部分に一致する場合は、リストの最初は空文字列から始まり、最後の部分に一致する場合はリストの最終要素が空文字列になる。

空文字列('')では分割されない。patternとして空文字1文字を指定するとエラー。

置換

sub()

re.sub(pattern, repl, string, count=0, flags=0)

string中でpatternにマッチする部分文字列をreplの文字列で置換する。countで正の整数値を指定すると、先頭から最大その回数だけ置換を行う。

空文字列とのマッチは、前のマッチの直後以外に置換される。

replには文字列を返す関数を指定できる。

subn()

re.subn(pattern, repl, string, count=0, fkags=0)

sub()と同じ操作を行うが、タプルで(置換後の文字列, 置換数)を返す。

 

Python3 – エスケープシーケンス

Pythonのエスケープシーケンス一覧

\\ バックスラッシュ('\')
\' シングルクォーテーション("'")
\" ダブルクォーテーション('"')
\a ベル
\b バックスペース
\f 改ページ
\r キャリッジリターン
\n 改行
\t 水平タブ
\v 垂直タブ
¥N{name} Unicodeデータベース中で名前nameを持つ文字
\uxxxx 16ビットの16進数xxxxを持つUnicode文字
\Uxxxxxxxx 32ビットの16進数xxxxxxxxを持つUnicode文字
\ooo 8進数oooを持つASCII文字
\xhh 16進数hhを持つASCII文字
\0 NULL
\+改行 改行の直前(文末)が\の場合は次の行が継続

 

Python3 – 正規表現

Pythonでの正規表現の扱い

Pythonでは、パターン・マッチングを以下のいずれかの方法で行い、その結果をMatchObjectオブジェクトとして返す。

  • パターンと文字列を指定して、reモジュールで定義された関数を実行する
  • パターン文字列を正規表現オブジェクトとしてコンパイルしておき、そのメソッドで文字列を指定して実行する

reモジュール関数を使う方法

モジュール関数で実行する例は次の通り。実行結果はMatchObjectのオブジェクトとして返されるが、その文字列表現のspanのところに4文字目~8-1文字目でヒットしたことが記録されている。

パターン文字列を正規表現オブジェクトにコンパイルする方法

正規表現オブジェクトにコンパイルして検索する方法は次の通り。検索結果は先と同じMatchObjectオブジェクト。

Python3 – 文字列とコレクション

リストと文字列

list()関数で文字列をリストに分解し、join()メソッドで区切り文字を''(空文字)で指定してリストを文字列に結合。

数値要素のリストを文字列要素のリストにするには、map()関数でstr()関数を適用する。

ただしmap()関数はいろいろと注意が必要

setと文字列

set()で文字列の重複した文字を集約したセットが得られる。文字列の順番は固定されず、実行ごとにも異なる。

 

 

Python3 – 文字列

内容の取得

文字列長

文字列長はlen()関数で得られる。

一文字取得

配列のように文字列中の位置を指定して、一文字取得する。開始位置は0。-1で最後の文字を指定でき、そこから順に-2、-3と先頭に向けて遡る。

イテレータ、リストによる連続取得

文字列はイテレータ。

list()関数で一文字ずつのリストが得られる。

文字の出現回数

count(sub[, start[, end]])は元の文字列の中の部分文字列subの出現回数を返す。startendはオプションで指定可能。

部分文字列の取得(スライス)

以下の記法で部分文字列を取り出せる。ただし取り出される最後の文字列は終了位置-1番目の文字。

具体例は以下の通り。

正のステップ値の場合は検索方向が左→右なので以下の関係でなければならない。

負のステップ値を使うと、最後尾から先頭へ向かって文字を取り出す。特にステップ値を-1とすると、1文字ずつ前へ向かって取り出すので、文字列の反転に便利。ただし開始位置と終了位置に注意が必要。

負のステップ値の場合には検索方向が右→左になるので、以下の関係でなければならない。

n文字目からm文字取得したい時。

スライスとfinde/rfindでは開始位置・終了位置の指定の考え方が違ってくる

特定文字での分割

split()メソッドは、指定した文字列で元の文字列を分解し、リストで返す。

partition()メソッドは指定文字の最初の出現位置で文字列を分割し、タプルで結果を返す。

内容の判定

stringオブジェクトの以下のメソッドは、それぞれの条件に合致した場合にTrueを返す。空文字列に対しては全てFalseを返す。

isalpha()
全ての文字がアルファベットの場合にTrue。
isdigit()
全ての文字が数字の場合にTrue。
isalnum()
全ての文字がアルファベットか数字の場合にTrue。
islower()
文字列中のアルファベットが全て小文字の場合にTrue。アルファベット以外の数字や記号が含まれていても判定対象外で無視されるが、アルファベットがまったく含まれていないとFalse。
isupper()
文字列中のアルファベットが全て大文字の場合にTrue。アルファベット以外の数字や記号が含まれていても判定対象外。アルファベット以外の数字や記号が含まれていても判定対象外で無視されるが、アルファベットがまったく含まれていないとFalse。
isspace()
全ての文字がスペースの場合にTrue。
istitle()
文字列中の区切られた部分文字列がタイトルケースの場合にTrue。

検索

find/rfind

find()は指定した文字列を検索し、そのインデックスを返す。存在しない場合は-1が返される。検索範囲の指定はスライスと同じで[開始位置, 終了位置)。

index()も同じ使い方ができるが、存在しない場合にValueError: substring not foundが返される。

rfind()は文字列の後方から検索する。開始位置と終了位置の意味はスライスと同じだが、開始位置だけ指定すると、そこから文字列の後方が検索範囲となってしまう点に注意。

find/rfindとスライスでの範囲指定が違ってくる点に注意

内容の変更

連結

+演算子で文字列を連結できる。

join()メソッドで、元の文字列オブジェクトを区切り文字にして、引数リストの各文字列要素を連結できる。

数値と文字列を連結する場合、Pythonでは自動変換されない。str()関数で明示的に文字列に変換する必要がある。

join()の方が推奨されているらしい。

繰り返し

*演算子で同じ文字列を複数回繰り返した文字列を得られる。

置き換え

replace(old, new[, count)メソッドは、部分文字列oldnewで置き換える。countが指定されると、先頭からその個数分だけ置き換える。

置き換え前後の部分文字列の長さが違ってもよい。置き換え後に空文字列を指定すると、文字列の削除に使える。

replace()のほか、sub()関数(reパッケージ)、str.translate()関数も使える。

なお、部分文字列をスライスで取得した書式を使って文字列を代入することはできず、エラーとなる。

書式・整形

センタリング・左寄せ・右寄せ

center()ljust()rjust()の各メソッドで、元の文字列を指定した幅の中でセンタリング・左寄せ・右寄せできる。デフォルトでは空いた場所がスペース(‘ ‘)で埋められるが、その文字を指定することが可能。

余白などの切り落とし

strip()lstrip()rstrip()各メソッドは、文字列の両端の指定文字を削除する。デフォルトでは空白が削除されるが、複数の文字を切り落とす対象として指定できる。

ただし、切り落とされるのは最も外側の文字列群だけであることに注意。