LoginSignup
0
1

More than 1 year has passed since last update.

正規表現覚え書き(python)

Last updated at Posted at 2021-12-20

完全な覚え書きメモ
参考:[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
0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1