正規表現

アサーション②

指定文字と1つ後の間で ...

 後読みは、任意に設定したパターンの後にマッチする正規表現です。

前回紹介した先読みとは、ちょうど逆の位置になります。

 表記は (?<= ) のようになります。

先読み(?= )の記述方法に似ていますが、後読みは < が必要になります。

例えば、(?<=¥) ならば ¥ とその後にある文字の間にマッチが生じます。

対象文字列が ¥5 €5 の場合 対象文字列が ¥5 €5 の場合のフローチャート\w


 先読みとの違いを示す為に、もう一つ例を挙げます。

指定する文字を a とするならば、先読みは (?=a),後読ならば、(?<=a) となります。

このパターンに対して、対象文字列が map の場合、下の図のように各々マッチします。

対象文字列が map の場合 対象文字列が map の場合のフローチャート\w


 この他に注意点として、後読みに指定する任意のパターンに、量指定子は利用出来ない点があります。

(量指定子 については【基礎5 量指定子】で詳しく説明します。)

先読みのときと同様に、シンプル、且つ最小構成な例を使い解説します。


この記事の難度は、基礎  Cクラスです。

(A: やさしい   →   E: 難しい)

 事前知識として、pythonから正規表現を扱う方法が必要になります。
また、正規表現における文字クラスの知識や、選択を表す正規表現である | OR(または) を理解している事が望ましいです。
(不安な人でも、【Pythonから使う】【基礎1 文字クラス】 【| OR(または)】、で詳しい解説があるので安心です。)
 シンプルな例を一個ずつ確認する事で、後読みに慣れていきます。
また、先読みとの違いを意識しましょう。

難度       :
事前知識: Pythonの基礎文法(reモジュールを含む)。正規表現の文字クラスや選択等。
学習効果:  後読みの性質である、任意に設定したパターンの後にマッチする、という事を理解出来る。

Contens  |   目次

Chapter1 Pythonで実行

Chapter1   Pythonで実行

(?<=a)

 先ず上記した例ですが、文字列パターンが (?<=a) の場合を考えます。

これは、a とその後にある文字の間にマッチします。

対象文字列が map なら a とその後にある p の間です。

    re_meta21_1.py

        import  re

        pattern = re.compile("(?<=a)")
        st = "map"
        print("↓ 対象文字列\n"+st)
        result_iter = pattern.finditer(st)
        for  result   in  result_iter:
            print("match:",result.group())
            print("位置",result.span())        
                            


実行結果 アサーション② (?<= ) 後読み_1

 予想通り、ap の間にマッチしました。

a を先頭や末尾にも並べて、 aaa のようにして実行してみます。

各々 a の後にヒットするはずです。

    re_meta21_2.py

        import  re

        pattern = re.compile("(?<=a)")
        st = "aaa"
        print("↓ 対象文字列\n"+st)
        result_iter = pattern.finditer(st)
        for  result   in  result_iter:
            print("match:",result.group())
            print("位置",result.span())        
                            


実行結果 アサーション② (?<= ) 後読み_2

 これも想定通りの結果です。

次に空白を挟んで、a a を対象文字列とします。

    re_meta21_3.py

        import  re

        # a と a の間は半角スペース
        pattern = re.compile("(?<=a)")
        st = "a a"
        print("↓ 対象文字列\n"+st)
        result_iter = pattern.finditer(st)
        for  result   in  result_iter:
            print("match:",result.group())
            print("位置",result.span())        
                            


実行結果 アサーション② (?<= ) 後読み_3

 スペースが存在しても、a の後にマッチするという性質は変わりません。

もう一つ例を挙げます。

文字列パターンが (?<=t) であり、対象文字列を teetotalism とする場合です。

    re_meta21_4.py

        import  re

        pattern = re.compile("(?<=t)")
        st = "teetotalism"
        print("↓ 対象文字列\n"+st)
        result_iter = pattern.finditer(st)
        for  result   in  result_iter:
            print("match:",result.group())
            print("位置",result.span())        
                            


実行結果 アサーション② (?<= ) 後読み_4

 それぞれ t の後にマッチしています。

今度は、(?<=t) だけでなく単語と組み合わせて使ってみます。

(?<=t)a

 対象文字列は、meta21_4.py と同様に teetotalism とします。

但し、文字列パターンを (?<=t)a とする事で、t の後にある a という文字にマッチします。

    re_meta21_5.py

        import  re

        pattern = re.compile("(?<=t)a")
        st = "teetotalism"
        print("↓ 対象文字列\n"+st)
        result_iter = pattern.finditer(st)
        for  result   in  result_iter:
            print("match:",result.group())
            print("位置",result.span())        
                            


実行結果 アサーション② (?<= ) 後読み_5

 狙い通り、a という文字に一致しました。

次の例では、通貨記号が ¥ である数字を取得します。

    re_meta21_6.py

        import  re

        pattern = re.compile("(?<=¥)\d")
        st = "¥5 3元 1¥ $9 £8 €7"
        print("↓ 対象文字列\n"+st)
        result_iter = pattern.finditer(st)
        for  result   in  result_iter:
            print("match:",result.group())
            print("位置",result.span())        
                            


実行結果 アサーション② (?<= ) 後読み_6

 ¥ 記号の後の数字を取得出来ました。

メタキャラクタと組み合わせて、¥ の他に の値もその対象にします。

(?= | )

 選択(OR)を表す正規表現は | です。

(| については【| OR(または)】で詳しく説明しています。)

(?<=¥|€)\d のようにすると、¥ の他に の後にある数字にマッチします。

    re_meta21_7.py

        import  re

        pattern = re.compile("(?<=¥|€)\d")
        st = "¥5 3元 1¥ $9 £8 €7"
        print("↓ 対象文字列\n"+st)
        result_iter = pattern.finditer(st)
        for  result   in  result_iter:
            print("match:",result.group())
            print("位置",result.span())        
                            


実行結果 アサーション② (?<= ) 後読み_7

 5円の他に7を得られました。

(?<= | ) のように、後読みと | を併用する場合の注意点として、選択(OR)の対象になる文字数が異なるとエラーが発生する事です。

例えば (?<=令和|R) のような場合です。

    re_meta21_8.py

        import  re

        pattern = re.compile("(?<=令和|R)")
        st = "8年 令和2年 R3年 平成5年"
        print("↓ 対象文字列\n"+st)
        result_iter = pattern.finditer(st)
        for  result   in  result_iter:
            print("match:",result.group())
            print("位置",result.span())        
                            


実行結果 アサーション② (?<= ) 後読み_8

 look-behind requires fixed-width pattern のエラーが発生しました。

これを回避するには、((?<=令和)|(?<=R)) のように変更します。

    re_meta21_9.py

        import  re

        pattern = re.compile("((?<=令和)|(?<=R))\d")
        st = "8年 令和2年 R3年 平成5年"
        print("↓ 対象文字列\n"+st)
        result_iter = pattern.finditer(st)
        for  result   in  result_iter:
            print("match:",result.group())
            print("位置",result.span())        
                            


実行結果 アサーション② (?<= ) 後読み_9

 無事にエラーの発生を避けられました。

似たような場合として、(?<=^|R) のような文字列パターンもエラーが生じます。

    re_meta21_10.py

        import  re

        pattern = re.compile("(?<=^|R)")
        st = "8年 令和2年 R3年 平成5年"
        print("↓ 対象文字列\n"+st)
        result_iter = pattern.finditer(st)
        for  result   in  result_iter:
            print("match:",result.group())
            print("位置",result.span())        
                            


実行結果 アサーション② (?<= ) 後読み_10

 このエラーの回避も、meta21_9.py と同様です。

    re_meta21_11.py

        import  re

        pattern = re.compile("((?<=^)|(?<=R))\d")
        st = "8年 令和2年 R3年 平成5年"
        print("↓ 対象文字列\n"+st)
        result_iter = pattern.finditer(st)
        for  result   in  result_iter:
            print("match:",result.group())
            print("位置",result.span())        
                            


実行結果 アサーション② (?<= ) 後読み_11

 問題無く処理できました。

また、後読みに指定する任意のパターンに、量指定子は利用出来ません。

(量指定子 については【基礎5 量指定子】で詳しく説明します。)

それ故に、(?<=\w*) とした場合にはエラーが発生します。

    re_meta21_12.py

        import  re

        pattern = re.compile("(?<=\w*)\d")
        st = "28年 令和2年 R3年 平成15年"
        print("↓ 対象文字列\n"+st)
        result_iter = pattern.finditer(st)
        for  result   in  result_iter:
            print("match:",result.group())
            print("位置",result.span())        
                            


実行結果 アサーション② (?<= ) 後読み_12

 look-behind requires fixed-width pattern のエラーです。

さて、この他にも ^ を使ってみます。

^ は、文字列の先頭を意味します。

(^ については【^ 行の先頭】で詳しく説明しています。)

 先頭の金額を抽出するには、以下のようにします。

    re_meta21_13.py

        import  re

        pattern = re.compile("(?<=^¥)\d")
        st = "¥2 ¥9 1¥ ¥0"
        print("↓ 対象文字列\n"+st)
        result_iter = pattern.finditer(st)
        for  result   in  result_iter:
            print("match:",result.group())
            print("位置",result.span())        
                            


実行結果 アサーション② (?<= ) 後読み_13

 ¥9¥0 ではなく、¥2を対象にできました。

続けて例を出します。

. の後にある数字を狙います。

. はそのまま使うと任意の1文字になってしまうので、\ (バックスラッシュ)と併用します。

(\ については【\ エスケープ文字の働き】で詳しく説明しています。)

    re_meta21_14.py

        import  re

        pattern = re.compile("(?<=\.)\d")
        st = "7.8 21.6 a.m"
        print("↓ 対象文字列\n"+st)
        result_iter = pattern.finditer(st)
        for  result   in  result_iter:
            print("match:",result.group())
            print("位置",result.span())        
                            


実行結果 アサーション② (?<= ) 後読み_14

 . の後にある数字のみを取得出来ました。



 後読みの説明はここで終了です。

多くの例をみてきたので、後読みの性質である、任意に設定したパターンの後にマッチする、という事を理解出来ました。

これにより、取得したい部分が、ある文字列の後にある場合に役立つでしょう。

 次回からは、否定先読み否定後読みに入ります。

関連記事

基礎4

\b 単語の境界

正規表現: アサーション②
難度       : 基礎
事前知識: Python基礎(reモジュール)。文字クラス等。
学習効果: 単語の境界とされる位置を的確に認識できるようになる。
基礎4

\B 単語の境界でない

正規表現: アサーション②
難度       : 基礎
事前知識: Python基礎(reモジュール)。文字クラス等。
学習効果: 単語の境界でない位置を的確に認識できるようになる。
基礎4

(?= ) 先読み

正規表現: アサーション②
難度       : 基礎
事前知識: Python基礎(reモジュール)。文字クラスや選択等。
学習効果: 先読みの性質である、任意に設定したパターンの前にマッチする、という事を理解出来る。
基礎4

(?<= ) 後読み

正規表現: アサーション②
難度       : 基礎
事前知識: Python基礎(reモジュール)。文字クラスや選択等。
学習効果: 後読みの性質である、任意に設定したパターンの後にマッチする、という事を理解出来る。
基礎4

(?! ) 否定先読み

正規表現: アサーション②
難度       : 基礎
事前知識: Python基礎(reモジュール)。文字クラスや選択等。
学習効果: 否定先読みの性質である、任意に設定したパターン以外の前でマッチする、という事を理解出来る。
基礎4

(?<! ) 否定後読み

正規表現: アサーション②
難度       : 基礎
事前知識: Python基礎(reモジュール)。文字クラスや選択等。
学習効果: 否定後読みの性質である、任意に設定したパターン以外の後でマッチする、という事を理解出来る。
Pythonで正規表現を使う1

正規表現をPythonから使うには ?

正規表現: Pythonから使う
難度       : 入門
事前知識: Pythonの基礎文法
学習効果: pythonから正規表現を使う一連の流れを掴む
メタキャラクタに馴染む_key-visual

ハロー ! メタキャラクタ

正規表現: メタキャラクタの概要
難度       : 入門
事前知識: 不要
学習効果: メタキャラクタの概要を掴む
正規表現の概要

正規表現とは?

正規表現: 概要
難度       : 入門
事前知識: 不要
学習効果: 正規表現の概要を知る
正規表現の概要

PR