完全な覚え書きメモ
参考:[https://ai-inter1.com/python-regex/#st-toc-h-1]
正規表現例
import re
URL = "http://www.amazon.co.jp/dp/B07T9TCPZX"
pattern = "https?://[^/]+/"
res = re.match(pattern, URL)
print(res.group()) # パターンにマッチした文字列を取得する
print(res.span()) # マッチした文字列の開始・終了位置を取得する
print(res.start()) # 開始位置を取得する
print(res.end()) # 終了位置を取得する
# http://www.amazon.co.jp/
# (0,24)
# 0
# 24
正規表現の関数
match
先頭の文字列からパターンに一致するものを検索する。
先頭から続いている物のみなので、途中で一致は検知しない。
match
# re.match(パターン, 検索文字列)
res = re.match("x.z","xyz") # "x.y" = x任意の1文字z
print(res)
# <re.Match object; span=(0, 3), match="xyz">
res = re.match("x.z","abcxyz") # "x.y" = x任意の1文字z
print(res)
# None
search
先頭からとは限らずパターンに一致するものを文中から検索、返す値は一つ目のみ。
search
# re.search(パターン, 検索文字列)
res = re.search("x.z","axyz")
print(res)
# <re.Match object; span=(1, 4), match='xyz'>
findall
パターンに一致したものを全てリストで返す、開始・終了位置は取得不可能。
findall
# re.findall(パターン, 検索文字列)
res = re.findall("x.z", "axyz bxaz xbz xcz")
print(res)
# ['xyz', 'xaz', 'xbz', 'xcz']
finditer
パターンに一致するものを全てmatchオブジェクト形式で取得可能。イテレータとして返り値が貰える。
finditer
# re.finditer(パターン, 検索文字列)
res = re.finditer("x.z", "axyz bxaz xbz xcz")
print(res)
for i in res:
print(i)
# <callable_iterator object at 0x0000018C3B103898>
# <re.Match object; span=(1, 4), match='xyz'>
# <re.Match object; span=(6, 9), match='xaz'>
# <re.Match object; span=(10, 13), match='xbz'>
# <re.Match object; span=(14, 17), match='xcz'>
fullmatch
文字列全体が一致しているかを確認。一致していた場合はmatch形式でreturn。
fullmatch
# re.fullmatch(パターン, 検索文字列)
res = re.fullmatch("x.z", "xaz")
print(res)
# <re.Match object; span=(0, 3), match='xaz'>
sub
パターンに一致した文字列を置き換える、一致しない場合は入力値を返答。
置き換えは数値でも可能。
sub
# re.sub(パターン, 置換する文字列,検索文字列)
res = re.sub("x.z", "OOO","abcxazdef")
print(res)
# abcOOOdef
正規表現記法(パターンの書き方)
任意の1文字 .
- 任意の1文字を表す
x.y = xyz
文章の先頭から検索させる ^
- 文章の頭からの検索を強制させる
- 頭から一致していない場合はNone
^
res = re.search("^ab", "abcde")
print(res)
# <_sre.SRE_Match object; span=(0, 2), match='ab'>
res = re.search("^ab", "xyz abcde")
print(res)
# None
文章の末尾から検索させる $
- 文章の末尾からの検索を強制させる
- 末尾から一致していない場合はNone
$
res = re.search("ab$", "cdeab")
print(res)
# <_sre.SRE_Match object; span=(3, 5), match='ab'>
res = re.search("ab$", "abcde")
print(res)
# None
0回もしくは1回繰り返し ?
- 直前の文字が0回もしくは1回繰り返されている
- 要は直前の文字が有る場合と無い場合が当てはまる
?
res = re.search("xy?", "x")
print(res.group())
# x
res = re.search("xy?", "xy")
print(res.group())
# xy
res = re.search("xy?", "xyy")
print(res.group())
# xy
0回以上繰り返し *
- 直前の文字が0回以上繰り返している場合
*
res = re.search("xy*", "x")
print(res)
# x
res = re.search("xy*", "xyyyyyyyyyyyyyyy")
print(res)
# xyyyyyyyyyyyyyyy
1回以上繰り返し +
- 直前の文字が1回以上繰り返している場合
+
res = re.search("xy+", "x")
print(res)
# None
res = re.search("xy*", "xyyyyyyyyyyyyyyy")
print(res)
# xyyyyyyyyyyyyyyy
n回繰り返し {n}
- 直前の文字がn回以上繰り返している場合
{n}
res = re.search("xy{2}", "xyy")
print(res)
# xyy
res = re.search("xy{2}", "xyyyyyyyyyyyy")
print(res)
# None
n回以上繰り返し {n,}
- 直前の文字がn回以上繰り返している場合
{n,}
res = re.search("xy{2,}", "xyy")
print(res)
# xyy
res = re.search("xy{2,}", "xyyyyyyyyyyyy")
print(res)
# xyyyyyyyyyyyy
n回以上、m回まで繰り返し {n,m}
- 直前の文字がn回以上でm回まで繰り返している場合
{n,}
res = re.search("xy{2,4}", "xyy")
print(res)
# xyy
res = re.search("xy{2,4}", "xyyyyyyyyyyyy")
print(res)
# xyyyy 残りのyは当てはまらない
文字列のグルーピング化 (~~~)
- 文字列をグルーピングする
- グルーピング化された文字列に繰り返しを充てることで、その文字列が繰り返されたかを確認可能。
- 例.
(ab){2} = abab
()
res = re.search("x(yz)+", "xyzyz")
print(res)
# xyzyz
res = re.search("x(yz)+", "xyzyzOyz")
print(res)
# xyzyz 0以下は連続が遮られたので一致しない
全ての数字 [0-9]
- 0-9のうちの数字であれば一致する
[0-9]
res = re.search("a[0-9]", "a1")
print(res)
# a1
res = re.search("a[0-9]+", "a123") # 連続で数値群を表せる
print(res)
# a123
全てのアルファベット(大文字小文字含む) [a-zA-Z]
- 大文字小文字を含む全てのアルファベット
- 小文字のみの場合は
[a-z]
- 大文字のみの場合は
[A-Z}
[a-zA-Z]
res = re.search("[a-zA-Z]", "a")
print(res)
# a
res = re.search("[a-zA-Z]+", "aBcDeFg") # 連続でアルファベットの文字列を表せる
print(res)
# aBcDeFg
全てのアルファベットと数字 [a-zA-Z0-9]
- 大文字小文字を含む全てのアルファベットと数字
[a-zA-Z0-9]
res = re.search("[a-zA-Z0-9]+", "ABC123")
print(res)
# ABC123
res = re.search("[a-zA-Z]+", "ABC_123") # 連続でアルファベットの文字列を表せる
print(res)
# ABC
全てのアルファベットと数字以外の記号 [^a-zA-Z0-9]
- ^(ハット)を付けることで上記
全て系統
の条件を否定できる - 上記
全て系統
を集合
と言う - アルファベット以外が欲しかったら
[^a-zA-Z]
の様な感じ
[^a-zA-Z0-9]
res = re.search("[^a-zA-Z0-9]+", "_?")
print(res)
# _?
res = re.search("[a-zA-Z]+", "ABC_123") # 連続でアルファベットの文字列を表せる
print(res)
# ABC
集合と集合の否定 [ ] or [^ ]
-
[]
で囲むことで集合が作れる - 例えばAと1と?のどれかが有れば一致としたい場合
[A1?]
とする - 逆にAと1と?のどれか以外であれば一致としたい場合
[^A1?]
とする - 集合の否定は何かが来るまでの様な形でも使える
- 例.
[^/]+
でabcd//
を検索するとabcd
まで抜き出せる - なにかの連続までとしたいときは
[^/{2}]+
res = re.search("[A1?]+", "A??11AABA")
print(res)
# A??11AA
res = re.search("[^/]+", "aiueo/kaki") # /まで
print(res)
# aiueo
res = re.search("[^/{2}]+", "aiueo//kaki") # //まで
print(res)
# aiueo
ある文字列よりも前を抜き出す (.*)(?=abc)
-
(.*)(?=abc)
でこの文字列よりも前を抜き出す
(.*)(?=abc)
res = re.search("(.*)(?=abc)", "ababba//abc")
print(res)
# ababba//
ある文字列よりも後を抜き出す (?<=abc)(.*)
-
(?<=abc)(.*)
でこの文字列よりも前を抜き出す
(?<=abc)(.*)
res = re.search("(?<=abc)(.*)", "ababcba//abc")
print(res)
# ba//abc 一番初めに来たabcから以下を取り出している
ORを使いたいとき (a|b)
- グルーピングで囲んで条件を付けることで文字列の条件式ができる
-
あいうえお|かきくけこ|さしすせそ
の様な形も可能 - 文字列の場合は
((ab)|(ac))
-
[ab]c
の様に[]
で囲むことでも可能
(a|b)
res = re.search("(a|b)+d", "abacd")
print(res)
# abacd
res = re.search("[ab]d", "bd")
print(res)
# bd
特殊シーケンス(よく使われる記法は以下で置き換えられる)
全ての数字([0-9]
) = \d
全ての数字以外([^0-9]
) = \D
全ての英数字(大文字小文字)とアンダーバー([a-zA-Z0-9_]
) = \w
全ての英数字(大文字小文字)とアンダーバー以外([^a-zA-Z0-9_]
) = \W
空白 = \s
空白以外 = \S
文字列の先頭(^
) = \A
文字列の末尾($
) = \Z
パターンをコンパイル
- パターンをコンパイルすることで、繰り返しパターンを描くことを省略できる
-
pattern = re.compile(パターン)
この様に.compile()
でコンパイルする
compile
# コンパイルしたものは以下の手法で使いまわせる
pattern = re.compile("xy+")
res = pattern.search("xyyyyyyyya") # コンパイルした変数.正規関数のメソッド("検索したい文章")
print(res.group())
特殊文字を調べたい場合
- パターンで使われるような特殊文字を検索したい場合は、その直前にバックスラッシュを付ける
-
\+
や\{}
の様な感じ - 特殊文字を含んだ文字列の場合は
(\{abc})
の様にグルーピングで囲む
貪欲マッチ・非貪欲マッチ
何回以上と繰り返しを設定するパターンにおいて、条件が一致する小さい文字列と、それを含む条件が一致する大きい文字列では、大きい文字列がreturnされる。(findallでも大きいものだけが検知される)
大きいものではなく最も小さいものを検索したい場合は、各繰り返し記号の直後に?
を付ける
貪欲・非貪欲
# 貪欲の場合
text = "<html><head></head><body></body></html>"
res = re.search("<.*>",text)
print(res)
# <html><head></head><body></body></html>
# 非貪欲の場合
text = "<html><head></head><body></body></html>"
res = re.search("<.*?>",text)
print(res)
# <html>
フラグ引数
パターンを記述する際にフラグ引数を加える事により、検索条件をパターン以外で操作することができる。
res = re.関数("パターン", "検索文字列", flags="フラグ引数")
pattern = re.compile("パターン",flags="フラグ引数")
大文字・小文字を区別しないフラグ引数
-
re.IGNORECAE
を使うことにより、文字列を検索する際に大文字小文字を判別しなくなる
IGNORECAE
res = re.search("[a-z]+","abcABC",flags=re.IGNORECASE)
print(res.group())
# abcABC
先頭・末尾からの検索を各行ごとにする
-
re.MULTILINE
を使うことにより、検索の開始位置を各行ごとにする(改行が含まれるときのみ) -
^
や$
を使用した場合、通常は改行があっても最も一番初めに来る文字列のみ参照される -
re.MULTILINE
により各行の先頭・末尾からの検索が可能となる
MULTILINE
text = """aiu123
kakiku123
sasisu123"""
res = re.findall("^[a-z]+", text)
print(res)
# ["aiu","kakiku","sasisu"]
パターンにコメントを追加する
-
re.VERBOSE
を使うことにより、#
以降がコメントとして認識される - 改行を行うとコメントとしての判断はなくなる
VERBOSE
# /をエスケープして検索している事に注意
pattern = re.compile("""
[0-9]{4}\/ #年/
[0-9]{1,2}\/ #月/
[0-9]{1,2} #日
""", re.VERBOSE)
res = pattern.findall("The date is 2020/10/23")
print(res)
# ["2020/10/23"]
パターンをグループ化し命名、それを参照する
-
(?P<グループ名>パターン)
で命名されたグルーピング化を行うことができる -
res = pattern.関数("検索したい文字列)
でパターンを適用し、res.関数("グループ名")
で命名グループに合った結果を出力する
grouping
pattern = re.compile("""
(?P<year>[0-9]{4})\/ #年/
(?P<month>[0-9]{1,2})\/ #月/
(?P<date>[0-9]{1,2}) #日
""", re.VERBOSE)
res = pattern.findall("The date is 2020/10/23") #ここでパターン中のグルーピングを適用し
print(res.group("year")) # ここで命名したものを呼んでいる
print(res.group("month"))
print(res.group("date"))
# 2020
# 10
# 30