6.2. re — 正規表現操作

ソースコード: Lib/re.py


このモジュールは、Perl などと同様の正規表現マッチング操作を提供しています。

Both patterns and strings to be searched can be Unicode strings (str) as well as 8-bit strings (bytes). However, Unicode strings and 8-bit strings cannot be mixed: that is, you cannot match a Unicode string with a byte pattern or vice-versa; similarly, when asking for a substitution, the replacement string must be of the same type as both the pattern and the search string.

正規表現では、特殊な形式を表したり、特殊文字の持つ特別な意味を呼び出さずにその特殊な文字を使えるようにするために、バックスラッシュ文字 ('\') を使います。こうしたバックスラッシュの使い方は、 Python の文字列リテラルにおける同じバックスラッシュ文字と衝突を起こします。例えば、バックスラッシュ自体にマッチさせるには、パターン文字列として '\\\\' と書かなければなりません、というのも、正規表現は \\ でなければならず、さらに正規な Python 文字列リテラルでは各々のバックスラッシュを \\ と表現せねばならないからです。

正規表現パターンに Python の raw string 記法を使えばこの問題を解決できます。 'r' を前置した文字列リテラル内ではバックスラッシュを特別扱いしません。従って、 "\n" が改行一文字の入った文字列になるのに対して、 r"\n"'\''n' という二つの文字の入った文字列になります。通常、 Python コード中では、パターンをこの raw string 記法を使って表現します。

大抵の正規表現操作が、モジュールレベルの関数と、 コンパイル済み正規表現 のメソッドとして提供されることに注意して下さい。関数は正規表現オブジェクトのコンパイルを必要としない近道ですが、いくつかのチューニング変数を失います。

参考

サードパーティの regex モジュールは、標準ライブラリの re モジュールと互換な API を持ち、追加の機能とより徹底した Unicode サポートを提供します。

6.2.1. 正規表現のシンタックス

正規表現 (すなわち RE) は、表現にマッチ (match) する文字列の集合を表しています。このモジュールの関数を使えば、ある文字列が指定の正規表現にマッチするか (または指定の正規表現がある文字列にマッチするか、つまりは同じことですが) を検査できます。

正規表現を連結すると新しい正規表現を作れます。 AB がともに正規表現であれば AB も正規表現です。一般的に、文字列 p が A とマッチし、別の文字列 q が B とマッチすれば、文字列 pq は AB にマッチします。ただし、この状況が成り立つのは、 AB との間に境界条件がある場合や、番号付けされたグループ参照のような、優先度の低い演算を AB が含まない場合だけです。かくして、ここで述べるような、より簡単でプリミティブな正規表現から、複雑な正規表現を容易に構築できます。正規表現に関する理論と実装の詳細については上記の Friedl 本か、コンパイラの構築に関する教科書を調べて下さい。

以下で正規表現の形式に関する簡単な説明をしておきます。より詳細な情報やよりやさしい説明に関しては、 正規表現 HOWTO を参照してください。

正規表現には、特殊文字と通常文字の両方を含められます。 'A''a' 、あるいは '0' のようなほとんどの通常文字は最も簡単な正規表現になります。こうした文字は、単純にその文字自体にマッチします。通常の文字は連結できるので、 last は文字列 'last' とマッチします。 (この節の以降の説明では、正規表現を引用符を使わずに この表示スタイル: special style で書き、マッチ対象の文字列は、 '引用符で括って' 書きます。)

Some characters, like '|' or '(', are special. Special characters either stand for classes of ordinary characters, or affect how the regular expressions around them are interpreted.

繰り返しの修飾子 (*, +, ?, {m,n} など) は直接入れ子にはできません。 これによって、非貪欲な修飾子の接尾辞 ? や他の実装での他の修飾子についての曖昧さを回避しています。 繰り返しのある正規表現の外側にさらに繰り返しを適用するには丸括弧が使えます。 例えば、正規表現 (?:a{6})* は6つの 'a' の0回以上の繰り返しに適合します。

特殊文字を以下に示します:

.
(ドット) デフォルトのモードでは改行以外の任意の文字にマッチします。 DOTALL フラグが指定されていれば改行も含むすべての文字にマッチします。
^
(キャレット) 文字列の先頭とマッチします。 MULTILINE モードでは各改行の直後にマッチします。
$
文字列の末尾、あるいは文字列の末尾の改行の直前にマッチします。例えば、 foo は 『foo』 と 『foobar』 の両方にマッチします。一方、正規表現 foo$ は 『foo』 だけとマッチします。興味深いことに、 'foo1\nfoo2\n'foo.$ で検索した場合、通常のモードでは 『foo2』 だけにマッチし、 MULTILINE モードでは 『foo1』 にもマッチします。 $ だけで 'foo\n' を検索した場合、2箇所 (内容は空) でマッチします: 1つは、改行の直前で、もう1つは、文字列の最後です。
*
直前にある RE に作用して、 RE を 0 回以上できるだけ多く繰り返したものにマッチさせるようにします。例えば ab* は 『a』、』ab』、あるいは 『a』 に任意個数の’b』 を続けたものにマッチします。
+
直前にある RE に作用して、 RE を、1 回以上繰り返したものにマッチさせるようにします。例えば ab+ は 『a』 に一つ以上の 『b』 が続いたものにマッチし、 『a』 単体にはマッチしません。
?
直前にある RE に作用して、 RE を 0 回か 1 回繰り返したものにマッチさせるようにします。例えば ab? は 『a』 あるいは 『ab』 にマッチします。
*?, +?, ??
The '*', '+', and '?' qualifiers are all greedy; they match as much text as possible. Sometimes this behaviour isn’t desired; if the RE <.*> is matched against '<a> b <c>', it will match the entire string, and not just '<a>'. Adding ? after the qualifier makes it perform the match in non-greedy or minimal fashion; as few characters as possible will be matched. Using the RE <.*?> will match only '<a>'.
{m}
前にある RE の m 回の正確なコピーとマッチすべきであることを指定します;マッチ回数が少なければ、RE 全体ではマッチしません。例えば、 a{6} は、正確に 6個の 'a' 文字とマッチしますが、 5個ではマッチしません。
{m,n}
Causes the resulting RE to match from m to n repetitions of the preceding RE, attempting to match as many repetitions as possible. For example, a{3,5} will match from 3 to 5 'a' characters. Omitting m specifies a lower bound of zero, and omitting n specifies an infinite upper bound. As an example, a{4,}b will match 'aaaab' or a thousand 'a' characters followed by a 'b', but not 'aaab'. The comma may not be omitted or the modifier would be confused with the previously described form.
{m,n}?
結果の RE は、前にある RE の m 回から n 回まで繰り返したもので、できるだけ 少なく 繰り返したものとマッチするように、マッチします。これは、前の修飾子の控え目バージョンです。例えば、 6文字文字列 'aaaaaa' では、 a{3,5} は、5個の 'a' 文字とマッチしますが、 a{3,5}? は3個の文字とマッチするだけです。
\

特殊文字をエスケープする( '*''?' 等のような文字とのマッチをできるようにする) か、あるいは、特殊シーケンスの合図です; 特殊シーケンスは後で議論します。

もしパターンを表現するのに raw string を使用していないのであれば、 Python も、バックスラッシュを文字列リテラルでのエスケープシーケンスとして使っていることを覚えていて下さい。エスケープシーケンスを Python の構文解析器が認識して処理しない場合、そのバックスラッシュとそれに続く文字は、結果の文字列にそのまま含まれます。しかし、Python が結果のシーケンスを認識する場合は、バックスラッシュを 2回繰り返さなければいけません。これは複雑で理解しにくいので、最も簡単な表現以外は、すべて raw string を使うことを強く推奨します。

[]

文字の集合を指定するのに使用します。集合には以下のものが指定できます:

  • 個別に指定できる文字。 [amk]'a', 'm', 'k' とマッチします。
  • Ranges of characters can be indicated by giving two characters and separating them by a '-', for example [a-z] will match any lowercase ASCII letter, [0-5][0-9] will match all the two-digits numbers from 00 to 59, and [0-9A-Fa-f] will match any hexadecimal digit. If - is escaped (e.g. [a\-z]) or if it’s placed as the first or last character (e.g. [-a] or [a-]), it will match a literal '-'.
  • 集合内では、特殊文字はその意味を失います。 [(+*)] はリテラル文字 '(' '+''*' 、あるいは ')' のいずれかとマッチします。
  • \w\S のような文字クラス (後述) も集合内に指定できますが、それらにマッチする文字は ASCIILOCALE のどちらか有効にされているモードに依存します。
  • 範囲内にない文字とは、その集合の 補集合 をとることでマッチできます。集合の最初の文字が '^' の時、集合に ない 文字すべてとマッチします。 [^5]'5' を除くあらゆる文字にマッチします。 [^^]'^' を除くあらゆる文字にマッチします。 ^ は集合の最初の文字でない限り特別の意味を持ちません。
  • 集合内でリテラル ']' をマッチさせるには、その前にバックスラッシュをつけるか、集合の先頭に置きます。 [()[\]{}][]()[{}] はどちらも ']' にマッチします。
|
A|B, where A and B can be arbitrary REs, creates a regular expression that will match either A or B. An arbitrary number of REs can be separated by the '|' in this way. This can be used inside groups (see below) as well. As the target string is scanned, REs separated by '|' are tried from left to right. When one pattern completely matches, that branch is accepted. This means that once A matches, B will not be tested further, even if it would produce a longer overall match. In other words, the '|' operator is never greedy. To match a literal '|', use \|, or enclose it inside a character class, as in [|].
(...)
Matches whatever regular expression is inside the parentheses, and indicates the start and end of a group; the contents of a group can be retrieved after a match has been performed, and can be matched later in the string with the \number special sequence, described below. To match the literals '(' or ')', use \( or \), or enclose them inside a character class: [(], [)].
(?...)
これは拡張記法です ('(' に続く '?' は他には意味がありません) 。 '?' の後の最初の文字が、この構造の意味とこれ以上のシンタックスがどういうものであるかを決定します。拡張記法は普通新しいグループを作成しません; (?P<name>...) がこの規則の唯一の例外です。以下に現在サポートされている拡張記法を示します。
(?aiLmsux)
(One or more letters from the set 'a', 'i', 'L', 'm', 's', 'u', 'x'.) The group matches the empty string; the letters set the corresponding flags: re.A (ASCII-only matching), re.I (ignore case), re.L (locale dependent), re.M (multi-line), re.S (dot matches all), re.U (Unicode matching), and re.X (verbose), for the entire regular expression. (The flags are described in モジュールコンテンツ.) This is useful if you wish to include the flags as part of the regular expression, instead of passing a flag argument to the re.compile() function. Flags should be used first in the expression string.
(?:...)
正規表現の丸括弧の取り込まないバージョンです。どのような正規表現が丸括弧内にあってもマッチしますが、グループによってマッチされたサブ文字列は、マッチを実行したあと検索されることも、あるいは後でパターンで参照されることも できません
(?imsx-imsx:...)

('i', 'm', 's', 'x' の集合にある文字を 0 個以上、それに続くオプショナルな '-' と先程と同じ集合にある文字を 1 個以上。) 正規表現の一部に対して、文字に対応するフラグ、re.I (大文字・小文字を区別しない), re.M (MULTILINE モード), re.S (DOTALL モード), re.X (冗長) を設定したり除去したりします。 (これらのフラグについては モジュールコンテンツ に解説があります。)

バージョン 3.6 で追加.

(?P<name>...)

正規表現の丸括弧に似ていますが、グループによってマッチした部分文字列はシンボリックグループ名 name によってアクセス可能になります。グループ名は有効な Python 識別子でなければならず、グループ名は 1 個の正規表現内で一意でなければなりません。シンボリックグループは番号付けもされており、番号によるアクセスも可能です。

名前付きグループは 3 つのコンテキストで参照できます。パターンが (?P<quote>['\"]).*?(?P=quote) (シングルまたはダブルクオートのどちらかにマッチ) の場合`:

グループ 「quote」 を参照するコンテキスト 参照方法
同一パターンへの参照
  • (?P=quote) (そのまま)
  • \1
when processing match object m
  • m.group('quote')
  • m.end('quote') (etc.)
in a string passed to the repl argument of re.sub()
  • \g<quote>
  • \g<1>
  • \1
(?P=name)
名前付きグループへの後方参照です; 既出のグループ名 name にマッチする文字列は何にでもマッチします。
(?#...)
コメントです;括弧の内容は単純に無視されます。
(?=...)
Matches if ... matches next, but doesn’t consume any of the string. This is called a lookahead assertion. For example, Isaac (?=Asimov) will match 'Isaac ' only if it’s followed by 'Asimov'.
(?!...)
Matches if ... doesn’t match next. This is a negative lookahead assertion. For example, Isaac (?!Asimov) will match 'Isaac ' only if it’s not followed by 'Asimov'.
(?<=...)

Matches if the current position in the string is preceded by a match for ... that ends at the current position. This is called a positive lookbehind assertion. (?<=abc)def will find a match in 'abcdef', since the lookbehind will back up 3 characters and check if the contained pattern matches. The contained pattern must only match strings of some fixed length, meaning that abc or a|b are allowed, but a* and a{3,4} are not. Note that patterns which start with positive lookbehind assertions will not match at the beginning of the string being searched; you will most likely want to use the search() function rather than the match() function:

>>> import re
>>> m = re.search('(?<=abc)def', 'abcdef')
>>> m.group(0)
'def'

この例ではハイフンに続く単語を探します:

>>> m = re.search('(?<=-)\w+', 'spam-egg')
>>> m.group(0)
'egg'

バージョン 3.5 で変更: 固定長のグループ参照をサポートするようになりました。

(?<!...)
文字列内の現在位置の前に ... とのマッチがない場合に、マッチします。これは 否定後読みアサーション(negative lookbehind assertion) と呼ばれます。肯定後読みアサーションと同様に、含まれるパターンは固定長さの文字列だけにマッチしなければなりません。否定後読みアサーションで始まるパターンは、検索される文字列の先頭とマッチできます。
(?(id/name)yes-pattern|no-pattern)
与えられたグループ id あるいは name が存在する場合、yes-pattern とのマッチを、存在しない場合 no-pattern とのマッチを試みます。no-pattern は省略可能です。例えば、(<)?(\w+@\w+(?:\.\w+)+)(?(1)>|$) は貧弱な E-mail マッチングパターンで、'<user@host.com>''user@host.com' にマッチしますが、'<user@host.com''user@host.com>' とはマッチしません。

The special sequences consist of '\' and a character from the list below. If the ordinary character is not an ASCII digit or an ASCII letter, then the resulting RE will match the second character. For example, \$ matches the character '$'.

\number
同じ番号のグループの中身とマッチします。グループは1から始まる番号をつけられます。例えば、 (.+) \1 は、 'the the' あるいは '55 55' とマッチしますが、 'thethe' とはマッチしません(グループの後のスペースに注意して下さい)。この特殊シーケンスは最初の 99 グループのうちの一つとマッチするのに使うことができるだけです。もし number の最初の桁が 0 である、すなわち number が 3 桁の8進数であれば、それはグループのマッチとは解釈されず、 8進数値 number を持つ文字として解釈されます。文字クラスの '['']' の中の数値エスケープは、文字として扱われます。
\A
文字列の先頭だけにマッチします。
\b

Matches the empty string, but only at the beginning or end of a word. A word is defined as a sequence of word characters. Note that formally, \b is defined as the boundary between a \w and a \W character (or vice versa), or between \w and the beginning/end of the string. This means that r'\bfoo\b' matches 'foo', 'foo.', '(foo)', 'bar foo baz' but not 'foobar' or 'foo3'.

By default Unicode alphanumerics are the ones used in Unicode patterns, but this can be changed by using the ASCII flag. Word boundaries are determined by the current locale if the LOCALE flag is used. Inside a character range, \b represents the backspace character, for compatibility with Python’s string literals.

\B
Matches the empty string, but only when it is not at the beginning or end of a word. This means that r'py\B' matches 'python', 'py3', 'py2', but not 'py', 'py.', or 'py!'. \B is just the opposite of \b, so word characters in Unicode patterns are Unicode alphanumerics or the underscore, although this can be changed by using the ASCII flag. Word boundaries are determined by the current locale if the LOCALE flag is used.
\d
ユニコード (str) パターンに対して:
任意の Unicode 10進数 (Unicode 文字カテゴリ [Nd]) とマッチします。これには [0-9] とその他の 10 進数文字が含まれます。ASCII が使用された場合、[0-9] のみマッチします。ただし、このフラグは正規表現全体に作用しますので、明示的に [0-9] と指定する方が良い場合があるかもしれません。
8bit (bytes) パターンに対して:
任意の 10 進数にマッチします; これは [0-9] と等価です。
\D
Matches any character which is not a decimal digit. This is the opposite of \d. If the ASCII flag is used this becomes the equivalent of [^0-9] (but the flag affects the entire regular expression, so in such cases using an explicit [^0-9] may be a better choice).
\s
ユニコード (str) パターンに対して:
任意の空白文字とマッチします。これには [ \t\n\r\f\v] およびノーブレークスペースなど、多くの言語におけるタイポグラフィ規則で定義された文字が含まれます。ASCII フラグを使用すると、[ \t\n\r\f\v] のみにマッチします。ただし、このフラグは正規表現全体に作用しますので、明示的に [ \t\n\r\f\v] と指定する方が良い場合があるかもしれません。
8bit (bytes) パターンに対して:
ASCII 文字セットにおける空白文字とマッチします。これは [ \t\n\r\f\v] と等価です。
\S
Matches any character which is not a whitespace character. This is the opposite of \s. If the ASCII flag is used this becomes the equivalent of [^ \t\n\r\f\v] (but the flag affects the entire regular expression, so in such cases using an explicit [^ \t\n\r\f\v] may be a better choice).
\w
ユニコード (str) パターンに対して:
任意の Unicode 単語文字にマッチします。これにはあらゆる言語で単語の一部になりうる文字、数字、およびアンダースコアが含まれます。ASCII フラグを使用すると [a-zA-Z0-9_] のみにマッチします。ただし、このフラグは正規表現全体に作用しますので、明示的に [a-zA-Z0-9_] と指定する方が良い場合があるかもしれません。
8bit (bytes) パターンに対して:
Matches characters considered alphanumeric in the ASCII character set; this is equivalent to [a-zA-Z0-9_]. If the LOCALE flag is used, matches characters considered alphanumeric in the current locale and the underscore.
\W
Matches any character which is not a word character. This is the opposite of \w. If the ASCII flag is used this becomes the equivalent of [^a-zA-Z0-9_] (but the flag affects the entire regular expression, so in such cases using an explicit [^a-zA-Z0-9_] may be a better choice). If the LOCALE flag is used, matches characters considered alphanumeric in the current locale and the underscore.
\Z
文字列の末尾とのみマッチします。

Python 文字列リテラルによってサポートされている標準エスケープのほとんども、正規表現パーザによって認識されます:

\a      \b      \f      \n
\r      \t      \u      \U
\v      \x      \\

(\b は単語の境界を表し、文字クラス内でのみ後退 (backspace) 文字を指すことに注意してください)

'\u' and '\U' escape sequences are only recognized in Unicode patterns. In bytes patterns they are errors.

8 進数エスケープは限られた形式で表します。最初の桁が 0 か、あるいは 3 桁の 8 進数ならば、8 進数エスケープとみなされます。それ以外の場合はグループ参照になります。文字列リテラルに関しては、8 進数エスケープはほとんどの場合 3 桁長になります。

バージョン 3.3 で変更: '\u''\U' エスケープシーケンスが追加されました。

バージョン 3.6 で変更: '\' と ASCII 文字からなる未知のエスケープはエラーになります。

参考

Mastering Regular Expressions 詳説正規表現
Jeffrey Friedl 著、O’Reilly 刊の正規表現に関する本です。この本の第2版ではPyhonについては触れていませんが、良い正規表現パターンの書き方を非常にくわしく説明しています。

6.2.2. モジュールコンテンツ

このモジュールはいくつかの関数、定数、例外を定義します。この関数の一部はコンパイルした正規表現の完全版メソッドを簡略化したバージョンです。簡単なアプリケーションを除くほとんどで、コンパイルされた形式が用いられるのが普通です。

バージョン 3.6 で変更: フラグ定数は、enum.IntFlag のサブクラスである RegexFlag のインスタンスになりました、

re.compile(pattern, flags=0)

Compile a regular expression pattern into a regular expression object, which can be used for matching using its match(), search() and other methods, described below.

式の動作は、 flags の値を指定することで加減することができます。値は以下の変数を、ビットごとの OR ( | 演算子)を使って組み合わせることができます。

シーケンス

prog = re.compile(pattern)
result = prog.match(string)

は、以下と同等です

result = re.match(pattern, string)

ただし、その式を一つのプログラムで何回も使う場合には、 re.compile() を使ってその結果の正規表現オブジェクトを再利用した方がより効率的です。

注釈

re.compile() に渡されてコンパイルされた最新のパターンと、モジュールレベルのマッチング関数はキャッシュされるので、一度に少しの正規表現しか使わないプログラムは正規表現のコンパイルについて心配する必要はありません。

re.A
re.ASCII

Make \w, \W, \b, \B, \d, \D, \s and \S perform ASCII-only matching instead of full Unicode matching. This is only meaningful for Unicode patterns, and is ignored for byte patterns. Corresponds to the inline flag (?a).

後方互換性のため、re.U フラグ (およびそれと同義の re.UNICODE と埋め込みで使用する (?u)) はまだ存在していますが、文字列のマッチのデフォルトが Unicode になった Python 3 では冗長です (そして Unicode マッチングではバイト列は扱えません)。

re.DEBUG

Display debug information about compiled expression. No corresponding inline flag.

re.I
re.IGNORECASE

Perform case-insensitive matching; expressions like [A-Z] will also match lowercase letters. Full Unicode matching (such as Ü matching ü) also works unless the re.ASCII flag is used to disable non-ASCII matches. The current locale does not change the effect of this flag unless the re.LOCALE flag is also used. Corresponds to the inline flag (?i).

Note that when the Unicode patterns [a-z] or [A-Z] are used in combination with the IGNORECASE flag, they will match the 52 ASCII letters and 4 additional non-ASCII letters: 『İ』 (U+0130, Latin capital letter I with dot above), 『ı』 (U+0131, Latin small letter dotless i), 『ſ』 (U+017F, Latin small letter long s) and 『K』 (U+212A, Kelvin sign). If the ASCII flag is used, only letters 『a』 to 『z』 and 『A』 to 『Z』 are matched (but the flag affects the entire regular expression, so in such cases using an explicit (?-i:[a-zA-Z]) may be a better choice).

re.L
re.LOCALE

Make \w, \W, \b, \B and case-insensitive matching dependent on the current locale. This flag can be used only with bytes patterns. The use of this flag is discouraged as the locale mechanism is very unreliable, it only handles one 「culture」 at a time, and it only works with 8-bit locales. Unicode matching is already enabled by default in Python 3 for Unicode (str) patterns, and it is able to handle different locales/languages. Corresponds to the inline flag (?L).

バージョン 3.6 で変更: re.LOCALE バイト列のパターンにのみ利用できます。re.ASCII とは同時に指定できません。

re.M
re.MULTILINE

When specified, the pattern character '^' matches at the beginning of the string and at the beginning of each line (immediately following each newline); and the pattern character '$' matches at the end of the string and at the end of each line (immediately preceding each newline). By default, '^' matches only at the beginning of the string, and '$' only at the end of the string and immediately before the newline (if any) at the end of the string. Corresponds to the inline flag (?m).

re.S
re.DOTALL

Make the '.' special character match any character at all, including a newline; without this flag, '.' will match anything except a newline. Corresponds to the inline flag (?s).

re.X
re.VERBOSE

This flag allows you to write regular expressions that look nicer and are more readable by allowing you to visually separate logical sections of the pattern and add comments. Whitespace within the pattern is ignored, except when in a character class, or when preceded by an unescaped backslash, or within tokens like *?, (?: or (?P<...>. When a line contains a # that is not in a character class and is not preceded by an unescaped backslash, all characters from the leftmost such # through the end of the line are ignored.

つまり、数字にマッチする下記のふたつの正規表現オブジェクトは、機能的に等価です。:

a = re.compile(r"""\d +  # the integral part
                   \.    # the decimal point
                   \d *  # some fractional digits""", re.X)
b = re.compile(r"\d+\.\d*")

Corresponds to the inline flag (?x).

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

string を走査し、正規表現 pattern がマッチする最初の場所を探して、対応する match オブジェクト を返します。文字列内にパターンにマッチする場所が無い場合は None を返します; これは文字列内のある場所で長さが 0 のマッチが見つかった場合とは異なることに注意してください。

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

もし string の先頭で 0 個以上の文字が正規表現 pattern とマッチすれば、対応する マッチオブジェクト インスタンスを返します。文字列がパターンとマッチしなければ、None を返します; これは長さゼロのマッチとは異なることに注意して下さい。

MULTILINE モードであっても、re.match() は文字列の先頭のみにマッチし、各行の先頭にはマッチしないことに注意してください。

string 内のどこでもマッチできるようにするには、代わりに search() を使ってください (search() vs. match() も参照してください)。

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

string 全体が正規表現 pattern にマッチした場合、対応する match オブジェクト を返します。文字列にパターンにマッチする場所が無い場合は None を返します; これは長さが 0 のマッチとは違うということを注意しておきます。

バージョン 3.4 で追加.

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

string を、pattern があるたびに分割します。キャプチャグループの丸括弧が pattern で使われていれば、パターン内のすべてのグループのテキストも結果のリストの一部として返されます。maxsplit がゼロでなければ、最大 maxsplit 個の分割が発生し、残りはリストの最終要素として返されます。

>>> re.split('\W+', 'Words, words, words.')
['Words', 'words', 'words', '']
>>> re.split('(\W+)', 'Words, words, words.')
['Words', ', ', 'words', ', ', 'words', '.', '']
>>> re.split('\W+', 'Words, words, words.', 1)
['Words', 'words, words.']
>>> re.split('[a-f]+', '0a3B9', flags=re.IGNORECASE)
['0', '3', '9']

If there are capturing groups in the separator and it matches at the start of the string, the result will start with an empty string. The same holds for the end of the string:

>>> re.split('(\W+)', '...words, words...')
['', '...', 'words', ', ', 'words', '...', '']

その場合、常に、分割要素が、分割結果のリストの相対的なインデックスに現れます。

注釈

split() doesn’t currently split a string on an empty pattern match. For example:

>>> re.split('x*', 'axbc')
['a', 'bc']

'x*' は 『a』 の前、 『b』 と 『c』 との間、 『c』 の後の 0 個の 『x』 にもマッチしますが、現在これらのマッチは無視されます。正しい動作 (空のマッチでも文字列を分割し、['', 'a', 'b', 'c', ''] を返す) は、Python の将来のバージョンで実装されます。これは、後方互換生のない変更であるため、移行期間中は FutureWarning が送出されます。

空の文字列のみとマッチするパターンは、現在文字列を全く分割しません。これは望ましい動作ではないため、Python 3.5 から ValueError が送出されます:

>>> re.split("^$", "foo\n\nbar\n", flags=re.M)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  ...
ValueError: split() requires a non-empty pattern match.

バージョン 3.1 で変更: オプションの flags 引数が追加されました。

バージョン 3.5 で変更: 空の文字列にマッチするパターンによって分割しようとすると、警告が送出されるようになりました。空の文字列のみとマッチするパターンは拒否されるようになりました。

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

patternstring へのマッチのうち、重複しない全てのマッチを文字列のリストとして返します。 string は左から右へと走査され、マッチは見つかった順番で返されます。パターン中に何らかのグループがある場合、グループのリストを返します。グループが複数定義されていた場合、タプルのリストになります。他のマッチの開始部分に接触しないかぎり、空のマッチも結果に含められます。

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

string 内の RE pattern の重複しないマッチの マッチオブジェクト を yield する イテレータ を返します。string は左から右へと走査され、マッチは見つかった順番で返されます。他のマッチの開始部分に接触しないかぎり、空のマッチも結果に含められます。

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

Return the string obtained by replacing the leftmost non-overlapping occurrences of pattern in string by the replacement repl. If the pattern isn’t found, string is returned unchanged. repl can be a string or a function; if it is a string, any backslash escapes in it are processed. That is, \n is converted to a single newline character, \r is converted to a carriage return, and so forth. Unknown escapes such as \& are left alone. Backreferences, such as \6, are replaced with the substring matched by group 6 in the pattern. For example:

>>> re.sub(r'def\s+([a-zA-Z_][a-zA-Z_0-9]*)\s*\(\s*\):',
...        r'static PyObject*\npy_\1(void)\n{',
...        'def myfunc():')
'static PyObject*\npy_myfunc(void)\n{'

If repl is a function, it is called for every non-overlapping occurrence of pattern. The function takes a single match object argument, and returns the replacement string. For example:

>>> def dashrepl(matchobj):
...     if matchobj.group(0) == '-': return ' '
...     else: return '-'
>>> re.sub('-{1,2}', dashrepl, 'pro----gram-files')
'pro--gram files'
>>> re.sub(r'\sAND\s', ' & ', 'Baked Beans And Spam', flags=re.IGNORECASE)
'Baked Beans & Spam'

The pattern may be a string or a pattern object.

省略可能な引数 count は、置換されるパターンの出現回数の最大値です; count は非負の整数でなければなりません。もし省略されるかゼロであれば、出現したものがすべて置換されます。パターンのマッチが空であれば、以前のマッチと隣合わせでない時だけ置換されますので、 sub('x*', '-', 'abc')'-a-b-c-' を返します。

文字列タイプ repl 引数では、上で述べた文字エスケープや後方参照の他に、 \g<name> は、 (?P<name>...) シンタックスで定義された name グループによるマッチ部分文字列を使用することになりますし、 \g<number> は対応するグループ番号への参照となります; \g<2> はつまり \2 と等価ですが、 \g<2>0 のような置換においても曖昧になりません。 \20 は、グループ 20への参照として解釈され、グループ 2 にリテラル文字 '0' が続いたものへの参照としては解釈されないかもしれません。後方参照 \g<0> は、RE とマッチするサブ文字列全体を置き換えます。

バージョン 3.1 で変更: オプションの flags 引数が追加されました。

バージョン 3.5 で変更: マッチしないグループは空文字列に置き換えられます。

バージョン 3.6 で変更: pattern 中に '\' と ASCII 文字からなる未知のエスケープがあると、エラーになります。

バージョン 3.5 で非推奨、バージョン 3.7 で削除予定。』』 および ASCII 文字からなる未知のエスケープは、非推奨の警告を送出し、Python 3.7 では禁止されます。

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

sub() と同じ操作を行いますが、タプル (new_string、 number_of_subs_made) を返します。

バージョン 3.1 で変更: オプションの flags 引数が追加されました。

バージョン 3.5 で変更: マッチしないグループは空文字列に置き換えられます。

re.escape(pattern)

Escape all the characters in pattern except ASCII letters, numbers and '_'. This is useful if you want to match an arbitrary literal string that may have regular expression metacharacters in it. For example:

>>> print(re.escape('python.exe'))
python\.exe

>>> legal_chars = string.ascii_lowercase + string.digits + "!#$%&'*+-.^_`|~:"
>>> print('[%s]+' % re.escape(legal_chars))
[abcdefghijklmnopqrstuvwxyz0123456789\!\#\$\%\&\'\*\+\-\.\^_\`\|\~\:]+

>>> operators = ['+', '-', '*', '/', '**']
>>> print('|'.join(map(re.escape, sorted(operators, reverse=True))))
\/|\-|\+|\*\*|\*

This functions must not be used for the replacement string in sub() and subn(), only backslashes should be escaped. For example:

>>> digits_re = r'\d+'
>>> sample = '/usr/sbin/sendmail - 0 errors, 12 warnings'
>>> print(re.sub(digits_re, digits_re.replace('\\', r'\\'), sample))
/usr/sbin/sendmail - \d+ errors, \d+ warnings

バージョン 3.3 で変更: '_' 文字がエスケープされなくなりました。

re.purge()

正規表現キャッシュをクリアします。

exception re.error(msg, pattern=None, pos=None)

これらの関数のいずれかに渡された文字列が有効な正規表現ではない (例: 括弧が対になっていない) 場合、またはコンパイル時やマッチング時になんらかのエラーが発生した場合に発生する例外です。文字列にパターンとマッチする部分がなくても、それはエラーではありません。エラーインスタンスには、次のような追加の属性があります。

msg

フォーマットされていないエラーメッセージです。

pattern

正規表現のパターンです。

pos

The index in pattern where compilation failed (may be None).

lineno

The line corresponding to pos (may be None).

colno

The column corresponding to pos (may be None).

バージョン 3.5 で変更: 追加の属性が追加されました。

6.2.3. 正規表現オブジェクト

コンパイル済み正規表現オブジェクトは以下のメソッドと属性をサポートします:

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

string を走査し、正規表現がマッチする最初の場所を探して、対応する match オブジェクト を返します。文字列内にパターンにマッチする場所がない場合は None を返します; これは文字列内のある場所で長さが 0 のマッチが見つかった場合とは異なることに注意してください。

省略可能な、2つ目の引数 pos は、 string のどこから探し始めるかを指定する index で、デフォルトでは 0 です。これは、文字列をスライスしてから検索するのと、完全には同じではありません。パターン文字 '^' は本当の文字列の先頭と、改行の直後にマッチしますが、検索を開始する index がマッチするとは限りません。

The optional parameter endpos limits how far the string will be searched; it will be as if the string is endpos characters long, so only the characters from pos to endpos - 1 will be searched for a match. If endpos is less than pos, no match will be found; otherwise, if rx is a compiled regular expression object, rx.search(string, 0, 50) is equivalent to rx.search(string[:50], 0).

>>> pattern = re.compile("d")
>>> pattern.search("dog")     # Match at index 0
<_sre.SRE_Match object; span=(0, 1), match='d'>
>>> pattern.search("dog", 1)  # No match; search doesn't include the "d"
regex.match(string[, pos[, endpos]])

string先頭の 0 個以上の文字がこの正規表現とマッチする場合、対応する マッチオブジェクト を返します。文字列がパタンーとマッチしない場合、None を返します。これは長さゼロのマッチとは異なることに注意してください。

The optional pos and endpos parameters have the same meaning as for the search() method.

>>> pattern = re.compile("o")
>>> pattern.match("dog")      # No match as "o" is not at the start of "dog".
>>> pattern.match("dog", 1)   # Match as "o" is the 2nd character of "dog".
<_sre.SRE_Match object; span=(1, 2), match='o'>

string 内のどこでもマッチできるようにするには、代わりに search() を使ってください (search() vs. match() も参照してください)。

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

string 全体がこの正規表現にマッチした場合、対応する match オブジェクト を返します。文字列にパターンにマッチする場所が無い場合は None を返します; これは長さが 0 のマッチとは違うということを注意しておきます。

The optional pos and endpos parameters have the same meaning as for the search() method.

>>> pattern = re.compile("o[gh]")
>>> pattern.fullmatch("dog")      # No match as "o" is not at the start of "dog".
>>> pattern.fullmatch("ogre")     # No match as not the full string matches.
>>> pattern.fullmatch("doggie", 1, 3)   # Matches within given limits.
<_sre.SRE_Match object; span=(1, 3), match='og'>

バージョン 3.4 で追加.

regex.split(string, maxsplit=0)

split() 関数と同様で、コンパイルしたパターンを使います。ただし、 match() と同じように、省略可能な pos, endpos 引数で検索範囲を指定することができます。

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

Similar to the findall() function, using the compiled pattern, but also accepts optional pos and endpos parameters that limit the search region like for search().

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

Similar to the finditer() function, using the compiled pattern, but also accepts optional pos and endpos parameters that limit the search region like for search().

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

sub() 関数と同様で、コンパイルしたパターンを使います。

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

subn() 関数と同様で、コンパイルしたパターンを使います。

regex.flags

正規表現のマッチングフラグです。これは compile() で指定されたフラグ、パターン内の (?...) インラインフラグ、およびパターンが Unicode 文字列だった時の UNICODE のような暗黙のフラグとの組み合わせになりなす。

regex.groups

パターンにあるキャプチャグループの数です。

regex.groupindex

(?P<id>) で定義された任意の記号グループ名の、グループ番号への辞書マッピングです。もし記号グループがパターン内で何も使われていなければ、辞書は空です。

regex.pattern

RE オブジェクトがコンパイルされたときに使用された元のパターン文字列です。

6.2.4. match オブジェクト

マッチオブジェクトは常にブール値 True を持ちます。 match()search() はマッチしなかった場合に None を返すので、単純な if ステートメントによってマッチしたかどうかをテストできます:

match = re.search(pattern, string)
if match:
    process(match)

マッチオブジェクトは以下のメソッドと属性をサポートしています:

match.expand(template)

テンプレート文字列 template に対し、sub() メソッドがするようなバックスラッシュ置換をして得られる文字列を返します。\n のようなエスケープは適切な文字に変換され、数値の後方参照 (\1, \2) と名前付きの後方参照 (\g<1>, \g<name>) は、対応するグループの内容で置き換えられます。

バージョン 3.5 で変更: マッチしないグループは空文字列に置き換えられます。

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

Returns one or more subgroups of the match. If there is a single argument, the result is a single string; if there are multiple arguments, the result is a tuple with one item per argument. Without arguments, group1 defaults to zero (the whole match is returned). If a groupN argument is zero, the corresponding return value is the entire matching string; if it is in the inclusive range [1..99], it is the string matching the corresponding parenthesized group. If a group number is negative or larger than the number of groups defined in the pattern, an IndexError exception is raised. If a group is contained in a part of the pattern that did not match, the corresponding result is None. If a group is contained in a part of the pattern that matched multiple times, the last match is returned.

>>> m = re.match(r"(\w+) (\w+)", "Isaac Newton, physicist")
>>> m.group(0)       # The entire match
'Isaac Newton'
>>> m.group(1)       # The first parenthesized subgroup.
'Isaac'
>>> m.group(2)       # The second parenthesized subgroup.
'Newton'
>>> m.group(1, 2)    # Multiple arguments give us a tuple.
('Isaac', 'Newton')

もし正規表現が (?P<name>...) シンタックスを使うならば、 groupN 引数は、それらのグループ名によってグループを識別する文字列であっても構いません。もし文字列引数がパターンのグループ名として使われていないものであれば、 IndexError 例外が発生します。

A moderately complicated example:

>>> m = re.match(r"(?P<first_name>\w+) (?P<last_name>\w+)", "Malcolm Reynolds")
>>> m.group('first_name')
'Malcolm'
>>> m.group('last_name')
'Reynolds'

Named groups can also be referred to by their index:

>>> m.group(1)
'Malcolm'
>>> m.group(2)
'Reynolds'

If a group matches multiple times, only the last match is accessible:

>>> m = re.match(r"(..)+", "a1b2c3")  # Matches 3 times.
>>> m.group(1)                        # Returns only the last match.
'c3'
match.__getitem__(g)

This is identical to m.group(g). This allows easier access to an individual group from a match:

>>> m = re.match(r"(\w+) (\w+)", "Isaac Newton, physicist")
>>> m[0]       # The entire match
'Isaac Newton'
>>> m[1]       # The first parenthesized subgroup.
'Isaac'
>>> m[2]       # The second parenthesized subgroup.
'Newton'

バージョン 3.6 で追加.

match.groups(default=None)

パターンにマッチしたすべてのサブグループを含む、パターン内で指定されたグループ数分の要素を持つタプルを返します。引数 default は、マッチに加わらなかったグループ用に使われ、デフォルトでは None です。

例えば:

>>> m = re.match(r"(\d+)\.(\d+)", "24.1632")
>>> m.groups()
('24', '1632')

If we make the decimal place and everything after it optional, not all groups might participate in the match. These groups will default to None unless the default argument is given:

>>> m = re.match(r"(\d+)\.?(\d+)?", "24")
>>> m.groups()      # Second group defaults to None.
('24', None)
>>> m.groups('0')   # Now, the second group defaults to '0'.
('24', '0')
match.groupdict(default=None)

Return a dictionary containing all the named subgroups of the match, keyed by the subgroup name. The default argument is used for groups that did not participate in the match; it defaults to None. For example:

>>> m = re.match(r"(?P<first_name>\w+) (?P<last_name>\w+)", "Malcolm Reynolds")
>>> m.groupdict()
{'first_name': 'Malcolm', 'last_name': 'Reynolds'}
match.start([group])
match.end([group])

group とマッチした部分文字列の先頭と末尾のインデックスを返します。 group は、デフォルトでは(マッチした部分文字列全体を意味する)ゼロです。 group が存在してもマッチに寄与しなかった場合は、 -1 を返します。マッチオブジェクト m および、マッチに寄与しなかったグループ g があって、グループ g とマッチしたサブ文字列 ( m.group(g) と同じ意味ですが ) は:

m.string[m.start(g):m.end(g)]

です。もし group が空文字列とマッチすれば、 m.start(group)m.end(group) と等しくなることに注意して下さい。例えば、 m = re.search('b(c?)', 'cba') とすると、 m.start(0) は 1 で、 m.end(0) は 2 であり、 m.start(1)m.end(1) はともに 2 であり、 m.start(2)IndexError 例外を発生します。

An example that will remove remove_this from email addresses:

>>> email = "tony@tiremove_thisger.net"
>>> m = re.search("remove_this", email)
>>> email[:m.start()] + email[m.end():]
'tony@tiger.net'
match.span([group])

マッチ m について、大きさ2のタプル (m.start(group), m.end(group)) を返します。もし group がマッチに寄与しなければ、(-1, -1) になります。また group はデフォルトでゼロです。

match.pos

正規表現オブジェクトsearch()match() に渡された pos の値です。これは RE エンジンがマッチを探し始める位置の文字列のインデックスです。

match.endpos

正規表現オブジェクトsearch()match() に渡された endpos の値です。これは RE エンジンがそれ以上は進まない位置の文字列のインデックスです。

match.lastindex

最後にマッチした取り込みグループの整数インデックスです。もしどのグループも全くマッチしなければ None です。例えば、 (a)b, ((a)(b))((ab)) といった表現が 'ab' に適用された場合、 lastindex == 1 となり、同じ文字列に (a)(b) が適用された場合には lastindex == 2 となるでしょう。

match.lastgroup

最後にマッチした取り込みグループの名前です。もしグループに名前がないか、あるいはどのグループも全くマッチしなければ None です。

match.re

The regular expression object whose match() or search() method produced this match instance.

match.string

match() または search() へ渡された文字列です。

6.2.5. 正規表現の例

6.2.5.1. ペアの確認

この例では、マッチオブジェクトの表示を少し美しくするために、下記の補助関数を使用します :

def displaymatch(match):
    if match is None:
        return None
    return '<Match: %r, groups=%r>' % (match.group(), match.groups())

あなたがポーカープログラムを書いているとします。プレイヤーの持ち札はそれぞれの文字が1枚のカードを意味する5文字の文字列によって表現されます。 「a」 はエース、 「k」 はキング、 「q」 はクイーン、 「j」 はジャック、 「t」 は10、そして 「2」 から 「9」 はそれぞれの数字のカードを表します。

To see if a given string is a valid hand, one could do the following:

>>> valid = re.compile(r"^[a2-9tjqk]{5}$")
>>> displaymatch(valid.match("akt5q"))  # Valid.
"<Match: 'akt5q', groups=()>"
>>> displaymatch(valid.match("akt5e"))  # Invalid.
>>> displaymatch(valid.match("akt"))    # Invalid.
>>> displaymatch(valid.match("727ak"))  # Valid.
"<Match: '727ak', groups=()>"

That last hand, "727ak", contained a pair, or two of the same valued cards. To match this with a regular expression, one could use backreferences as such:

>>> pair = re.compile(r".*(.).*\1")
>>> displaymatch(pair.match("717ak"))     # Pair of 7s.
"<Match: '717', groups=('7',)>"
>>> displaymatch(pair.match("718ak"))     # No pairs.
>>> displaymatch(pair.match("354aa"))     # Pair of aces.
"<Match: '354aa', groups=('a',)>"

どのカードのペアになっているかを調べるには、以下のようにマッチオブジェクトの group() メソッドを使います:

>>> pair.match("717ak").group(1)
'7'

# Error because re.match() returns None, which doesn't have a group() method:
>>> pair.match("718ak").group(1)
Traceback (most recent call last):
  File "<pyshell#23>", line 1, in <module>
    re.match(r".*(.).*\1", "718ak").group(1)
AttributeError: 'NoneType' object has no attribute 'group'

>>> pair.match("354aa").group(1)
'a'

6.2.5.2. scanf() をシミュレートする

Python には現在のところ、 scanf() に相当するものがありません。正規表現は、 scanf() のフォーマット文字列よりも、一般的により強力であり、また冗長でもあります。以下の表に、 scanf() のフォーマットトークンと正規表現の大体同等な対応付けを示します。

scanf() トークン 正規表現
%c .
%5c .{5}
%d [-+]?\d+
%e, %E, %f, %g [-+]?(\d+(\.\d*)?|\.\d+)([eE][-+]?\d+)?
%i [-+]?(0[xX][\dA-Fa-f]+|0[0-7]*|\d+)
%o [-+]?[0-7]+
%s \S+
%u \d+
%x, %X [-+]?(0[xX])?[\dA-Fa-f]+

以下のような文字列からファイル名と数値を抽出することを考えます

/usr/sbin/sendmail - 0 errors, 4 warnings

scanf() フォーマットは次のように使います

%s - %d errors, %d warnings

同等な正規表現はこのようなものとなります

(\S+) - (\d+) errors, (\d+) warnings

6.2.5.3. search() vs. match()

Python は正規表現ベースの 2 個の基本的な関数、文字列の先頭でのみのマッチを確認する re.match() および、文字列内の位置にかかわらずマッチを確認する re.search() (Perl でのデフォルトの挙動) を提供しています。

例えば:

>>> re.match("c", "abcdef")    # No match
>>> re.search("c", "abcdef")   # Match
<_sre.SRE_Match object; span=(2, 3), match='c'>

'^' で始まる正規表現は、 search() において、マッチを文字列の先頭からに制限するために使用します:

>>> re.match("c", "abcdef")    # No match
>>> re.search("^c", "abcdef")  # No match
>>> re.search("^a", "abcdef")  # Match
<_sre.SRE_Match object; span=(0, 1), match='a'>

Note however that in MULTILINE mode match() only matches at the beginning of the string, whereas using search() with a regular expression beginning with '^' will match at the beginning of each line.

>>> re.match('X', 'A\nB\nX', re.MULTILINE)  # No match
>>> re.search('^X', 'A\nB\nX', re.MULTILINE)  # Match
<_sre.SRE_Match object; span=(4, 5), match='X'>

6.2.5.4. 電話帳の作成

split() は文字列を与えられたパターンで分割し、リストにして返します。下記の、電話帳作成の例のように、このメソッドはテキストデータを読みやすくしたり、 Python で編集したりしやすくする際に、非常に役に立ちます。

First, here is the input. Normally it may come from a file, here we are using triple-quoted string syntax:

>>> text = """Ross McFluff: 834.345.1254 155 Elm Street
...
... Ronald Heathmore: 892.345.3428 436 Finley Avenue
... Frank Burger: 925.541.7625 662 South Dogwood Way
...
...
... Heather Albrecht: 548.326.4584 919 Park Place"""

個々の記録は、1つ以上の改行で区切られています。まずは、文字列から空行を除き、記録ごとのリストに変換しましょう。

>>> entries = re.split("\n+", text)
>>> entries
['Ross McFluff: 834.345.1254 155 Elm Street',
'Ronald Heathmore: 892.345.3428 436 Finley Avenue',
'Frank Burger: 925.541.7625 662 South Dogwood Way',
'Heather Albrecht: 548.326.4584 919 Park Place']

そして、各記録を、名、姓、電話番号、そして、住所に分割してリストにします。分割のためのパターンに使っている空白文字が、住所には含まれるため、 split()maxsplit 引数を使います。 :

>>> [re.split(":? ", entry, 3) for entry in entries]
[['Ross', 'McFluff', '834.345.1254', '155 Elm Street'],
['Ronald', 'Heathmore', '892.345.3428', '436 Finley Avenue'],
['Frank', 'Burger', '925.541.7625', '662 South Dogwood Way'],
['Heather', 'Albrecht', '548.326.4584', '919 Park Place']]

パターン、 :? は姓に続くコロンにマッチします。そのため、コロンは分割結果のリストには現れません。 maxsplit4 にすれば、ハウスナンバーと、ストリート名を分割することができます。 :

>>> [re.split(":? ", entry, 4) for entry in entries]
[['Ross', 'McFluff', '834.345.1254', '155', 'Elm Street'],
['Ronald', 'Heathmore', '892.345.3428', '436', 'Finley Avenue'],
['Frank', 'Burger', '925.541.7625', '662', 'South Dogwood Way'],
['Heather', 'Albrecht', '548.326.4584', '919', 'Park Place']]

6.2.5.5. テキストの秘匿

sub() はパターンにマッチした部分を文字列や関数の返り値で置き換えます。この例では、」秘匿」 する文字列に、関数と共に sub() を適用する例を示します。言い換えると、最初と最後の文字を除く、単語中の文字の位置をランダム化します。

>>> def repl(m):
...     inner_word = list(m.group(2))
...     random.shuffle(inner_word)
...     return m.group(1) + "".join(inner_word) + m.group(3)
>>> text = "Professor Abdolmalek, please report your absences promptly."
>>> re.sub(r"(\w)(\w+)(\w)", repl, text)
'Poefsrosr Aealmlobdk, pslaee reorpt your abnseces plmrptoy.'
>>> re.sub(r"(\w)(\w+)(\w)", repl, text)
'Pofsroser Aodlambelk, plasee reoprt yuor asnebces potlmrpy.'

6.2.5.6. 全ての副詞を見つける

findall() matches all occurrences of a pattern, not just the first one as search() does. For example, if one was a writer and wanted to find all of the adverbs in some text, he or she might use findall() in the following manner:

>>> text = "He was carefully disguised but captured quickly by police."
>>> re.findall(r"\w+ly", text)
['carefully', 'quickly']

6.2.5.7. 全ての副詞と、その位置を見つける

If one wants more information about all matches of a pattern than the matched text, finditer() is useful as it provides match objects instead of strings. Continuing with the previous example, if one was a writer who wanted to find all of the adverbs and their positions in some text, he or she would use finditer() in the following manner:

>>> text = "He was carefully disguised but captured quickly by police."
>>> for m in re.finditer(r"\w+ly", text):
...     print('%02d-%02d: %s' % (m.start(), m.end(), m.group(0)))
07-16: carefully
40-47: quickly

6.2.5.8. Raw String記法

Raw string notation (r"text") keeps regular expressions sane. Without it, every backslash ('\') in a regular expression would have to be prefixed with another one to escape it. For example, the two following lines of code are functionally identical:

>>> re.match(r"\W(.)\1\W", " ff ")
<_sre.SRE_Match object; span=(0, 4), match=' ff '>
>>> re.match("\\W(.)\\1\\W", " ff ")
<_sre.SRE_Match object; span=(0, 4), match=' ff '>

When one wants to match a literal backslash, it must be escaped in the regular expression. With raw string notation, this means r"\\". Without raw string notation, one must use "\\\\", making the following lines of code functionally identical:

>>> re.match(r"\\", r"\\")
<_sre.SRE_Match object; span=(0, 1), match='\\'>
>>> re.match("\\\\", r"\\")
<_sre.SRE_Match object; span=(0, 1), match='\\'>

6.2.5.9. トークナイザを書く

トークナイザやスキャナ は文字列を解析し、文字のグループにカテゴリ分けします。これはコンパイラやインタプリタを作成する最初の一歩として役立ちます。

テキストのカテゴリは正規表現で指定されます。技術的には、それらを一つのマスター正規表現に結合し、連続したマッチをループさせます:

import collections
import re

Token = collections.namedtuple('Token', ['typ', 'value', 'line', 'column'])

def tokenize(code):
    keywords = {'IF', 'THEN', 'ENDIF', 'FOR', 'NEXT', 'GOSUB', 'RETURN'}
    token_specification = [
        ('NUMBER',  r'\d+(\.\d*)?'),  # Integer or decimal number
        ('ASSIGN',  r':='),           # Assignment operator
        ('END',     r';'),            # Statement terminator
        ('ID',      r'[A-Za-z]+'),    # Identifiers
        ('OP',      r'[+\-*/]'),      # Arithmetic operators
        ('NEWLINE', r'\n'),           # Line endings
        ('SKIP',    r'[ \t]+'),       # Skip over spaces and tabs
        ('MISMATCH',r'.'),            # Any other character
    ]
    tok_regex = '|'.join('(?P<%s>%s)' % pair for pair in token_specification)
    line_num = 1
    line_start = 0
    for mo in re.finditer(tok_regex, code):
        kind = mo.lastgroup
        value = mo.group(kind)
        if kind == 'NEWLINE':
            line_start = mo.end()
            line_num += 1
        elif kind == 'SKIP':
            pass
        elif kind == 'MISMATCH':
            raise RuntimeError(f'{value!r} unexpected on line {line_num}')
        else:
            if kind == 'ID' and value in keywords:
                kind = value
            column = mo.start() - line_start
            yield Token(kind, value, line_num, column)

statements = '''
    IF quantity THEN
        total := total + price * quantity;
        tax := price * 0.05;
    ENDIF;
'''

for token in tokenize(statements):
    print(token)

トークナイザは以下の出力を作成します:

Token(typ='IF', value='IF', line=2, column=4)
Token(typ='ID', value='quantity', line=2, column=7)
Token(typ='THEN', value='THEN', line=2, column=16)
Token(typ='ID', value='total', line=3, column=8)
Token(typ='ASSIGN', value=':=', line=3, column=14)
Token(typ='ID', value='total', line=3, column=17)
Token(typ='OP', value='+', line=3, column=23)
Token(typ='ID', value='price', line=3, column=25)
Token(typ='OP', value='*', line=3, column=31)
Token(typ='ID', value='quantity', line=3, column=33)
Token(typ='END', value=';', line=3, column=41)
Token(typ='ID', value='tax', line=4, column=8)
Token(typ='ASSIGN', value=':=', line=4, column=12)
Token(typ='ID', value='price', line=4, column=15)
Token(typ='OP', value='*', line=4, column=21)
Token(typ='NUMBER', value='0.05', line=4, column=23)
Token(typ='END', value=';', line=4, column=27)
Token(typ='ENDIF', value='ENDIF', line=5, column=4)
Token(typ='END', value=';', line=5, column=9)