Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Pythonで始める正規表現入門

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
Avatar for NobuakiOshiro NobuakiOshiro PRO
September 18, 2019

 Pythonで始める正規表現入門

Avatar for NobuakiOshiro

NobuakiOshiro PRO

September 18, 2019

More Decks by NobuakiOshiro

Other Decks in Technology

Transcript

  1. ⾃⼰紹介 • NOB DATA株式会社 代表取締役 • ⼤城 信晃 (@doradora09) •

    データサイエンティスト • 沖縄 -> 東京 -> 福岡(3年⽬) • ヤフー -> DATUM STUDIO -> LINE Fukuoka -> NOB DATA(株) 設⽴ • DS協会九州⽀部 発起⼈ • コミュニティ運営 • Tokyo.R, fukuoka.R, 意思決定のための データ分析勉強会, PyData.Fukuoka、等 https://nobdata.co.jp/ 2
  2. 正規表現とは • 正規表現(せいきひょうげん、英: regular expression)とは、 ⽂字列の集合を⼀つの⽂字列で表現する⽅法の⼀つである。正 則表現(せいそくひょうげん)とも呼ばれ、形式⾔語理論の分 野では⽐較的こちらの訳語の⽅が使われる。まれに正規式と呼 ばれることもある。(wikipediaより) •

    正規表現の起源の⼀つとして、数学者のスティーヴン・クリー ネは1950年代に正規集合と呼ばれる独⾃の数学的表記法を⽤い、 これらの分野のモデルを記述した。 • (その後Unix系のツールへ広がり今に⾄る)
  3. 正規表現のメリット • テキスト処理で本領を発揮。スクレイピングにも使える • XML(HTML含む)の構造が崩れているデータにも適⽤出来る • さらに他の⾔語でも使えるので汎⽤的 • ed、 grep、expr、awk、Emacs、vi、lex、Perl、PHP、Python等

    • windowsやmacで動くテキストエディタにも実装されてるものも。 ※注 • いくつか⽅⾔はあるので注意。共通して使えるものを覚えておくと吉。 • 基本正規表現、拡張正規表現、Perl⾵正規表現など
  4. 正規表現で出来ること(⼀例) プログラムのif⽂や専⽤関数を使わずに以下のようなことが可能 1. 区切り⽂字変更(タブ -> カンマ) 2. HTMLタグの除去(簡易版) 3. 都道府県の抽出(簡易版)

    4. 郵便番号の抽出(7桁) 5. URL解体(簡易版) 6. Emailアドレス形式チェック(⼀致するか否か) その他にも、⽂字列のルールに基づくマッチングや置換全般
  5. Pythonで正規表現使うならreモジュール • (恐らく)頭⽂字からre • 正規表現(せいきひょうげん、英: regular expression) • import reで使える

    • 解説 • このモジュールは Perl に⾒られる正規表現マッチング操作と同様のものを提供しま す。 • 正規表現では、特殊な形式を表すためや、特殊⽂字をその特殊な意味を発動させず 使うために、バックスラッシュ⽂字 ('\') を使います。 • 'r' を前置した⽂字列リテラル内ではバックスラッシュが特別扱いされません。従っ て "\n" が改⾏⼀⽂字からなる⽂字列であるのに対して、 r"\n" は '\' と 'n' の⼆⽂字 からなる⽂字列です。通常、 Python コード中では、パターンをこの raw ⽂字列記 法を使って表現します。 https://docs.python.org/ja/3/library/re.html
  6. reモジュールで使える関数 • re.sub : (正規表現による)置換 • re.search : マッチする最初のマッチオブジェクトを返却 •

    re.match : マッチした部分を取り出す (groupと併⽤) • re.findall : マッチした部分を全てリストに格納 ・・・ 正規表現を利⽤したマッチ処理が可能になる
  7. ご参考 : raw⽂字表記法のありなし #通常の表記 >>> print("aaa\nbbb\nccc") aaa bbb ccc #正規表現の改⾏として扱われる

    (エスケープシーケンス, 特殊⽂ 字とも) #raw⽂字の表記 >>> print(r"aaa\nbbb\nccc") aaa\nbbb\nccc #単なる⽂字列の\として扱われ る 特殊⽂字が含まれる⽂字列へのパターンマッチを⾏う 場合はraw⽂字表記の⽅がシンプルに書けるかも(後述)
  8. Python上で正規表現を試してみる ①区切り⽂字変更(タブ -> カンマ) \tがタブを表す パターン例 : \t import re

    a = 'aaa\tbbb\tccc' print(a) > aaa bbb ccc pattern = '\tʼ replacement = ',' b = re.sub(pattern, replacement, a) print(b) > aaa,bbb,ccc re.subで正規表現を使った 置換が可能 re.sub(パターン⽂字列, 置換後⽂字列, 対象⽂字列)
  9. Python上で正規表現を試してみる ③都道府県の抽出(簡易版) スペース以外の⽂字([^ ])が、 2⽂字から3⽂字続き{2,3}?、 かつ都道府県のいずれかが続く パターンにマッチ ※[]の中の^は否定を表す。 ⾏頭を⽰す^とは別の意味な ので注意

    パターン例 : ([^ ]{2,3}?[都道府県]) a = '〒810-0801 福岡県博多区中洲 3 丁⽬ 7-24' print(a) > 〒810-0801 福岡県博多区中洲 3 丁⽬ 7-24 pattern = '([^ ]{2,3}?[都道府県])' b = re.search(pattern, a) print(b[0]) > 福岡県 先頭にマッチした部分を格納する関数 re.serarch(パターン⽂字列、対象⽂字列) ※複数のマッチした部分を取りたい場合は re.findall関数を使う
  10. Python上で正規表現を試してみる ④郵便番号の抽出(7桁) 〒で始まり、 数字3⽂字(\d{3})、 ついでハイフン、 ついで数字4⽂字(\d{4}) のパターンにマッチ ※raw記法を使わない場合は バックスラッシュが2つ必 要(ここでは\マーク)

    パターン例 : 〒\\d{3}-\\d{4} a = '〒810-0801 福岡県博多区中洲 3 丁⽬ 7-24' print(a) > 〒810-0801 福岡県博多区中洲 3 丁⽬ 7-24 pattern = r'〒\d{3}-\d{4}' #または pattern = '〒\\d{3}-\\d{4}' b = re.search(pattern, a) print(b[0]) > 〒810-0801
  11. Python上で正規表現を試してみる ⑤URL解体(簡易版) ()でそれぞれグループ化したもの が分割されて後から取り出せる (後⽅参照) パターン例 : ^(.+?)://(.+?):?(\\d+)?(/.*)?$ a =

    'http://example.com:80/test/index.php' print(a) > http://example.com:80/test/index.php pattern = r'^(.+?)://(.+?):?(\d+)?(/.*)?$' b = re.search(pattern, a) print(b.group(0)) > http://example.com:80/test/index.php print(b.group(1)) > http print(b.group(2)) > example.com print(b.group(3)) > 80 groupを使う。 0は全体、1から順に ()でマッチ した部分が取り出せる
  12. Python上で正規表現を試してみる ⑥Emailアドレス形式チェック(⼀致するか否か) パターンに⼀致する場合は TRUEを返却 (!= Noneの条件判定を利⽤) 不⼀致の場合は FALSEを返却 パターン例 :

    ^[A-Za-z0-9._+]+@[A-Za-z]+.[A-Za-z]+$ a = '[email protected]' print(a) > [email protected] pattern = r'[A-Za-z0-9._+]+@[A-Za-z]+.[A-Za-z]+ʼ #または pattern = '^[A-Za-z0-9\._+]+@[A-Za-z]+\.[A-Za-z]+$' b = re.match(pattern, a) != None print(b) > True c = '[email protected]@dummy' d = re.match(pattern, c) != None print(d) > False ドットはメタ⽂字なのでバック スラッシュ(or\)でエスケープす るかraw⽂字記法を使う