正規表現 入門

79
正規表現 入門 2013.9.21 @姫路IT系勉強会 Vol.20 @spark6251 (N@N)

description

姫路IT系勉強会で発表した内容に加筆・修正を加えたものです.

Transcript of 正規表現 入門

Page 1: 正規表現 入門

正規表現 入門 2013.9.21 @姫路IT系勉強会 Vol.20 @spark6251 (N@N)

Page 2: 正規表現 入門

自己紹介 • N@N(@spark6251) • N@N→NOaN→NOAN→ノアン • 明石高専 電気情報工学科四年生 • プログラミングあんまりしてない • たぶんWeb屋

Page 3: 正規表現 入門

内容 • 正規表現基礎 • 実用例 • 有限オートマトン • 正規表現の動作原理 • まとめ

Page 4: 正規表現 入門

1. 正規表現基礎 • 基本的な正規表現の文法を学ぶ • 問題解決の手法の探索

Page 5: 正規表現 入門

目的 • 特定の条件で置換したいとか • 指定した行のテキストだけ出力したいとか • 検索したいとか

• 基礎を覚えるだけでも(それなりに広い場所

で)かなり使えるのが正規表現(つよい)

Page 6: 正規表現 入門

マッチする • .は”任意の1文字にマッチする” • match:釣り合う,相当する. • 意味合い的には一致するが近い • ”一致する”では双方向 • ”マッチする”は片方向

Page 7: 正規表現 入門

正規表現とは • 様々な用途に対応できるパターン言語 • パターン言語はパターンを要素とした規則シス

テムのようなもの • その言語とパターンそのものが正規表現

Page 8: 正規表現 入門

構成 • メタ文字:特殊な意味を持つもの.*とか?とか • リテラル:literal.普通の文字.大文字小文字

は区別される • ファイル名パターンでは*(ワイルドカード)など

が存在するが正規表現との違いはメタ文字による表現力の差である

• Regular expressions are easy!

Page 9: 正規表現 入門

egrep • 単純なテキストの検索 • 単語とか行だとかは認識しない • 各ファイルの各行でマッチする部分が見つかっ

た行を表示する • 最初の引数を文字列パターン,以下の引数を

ファイルと認識する.正規表現を使用するなら''で囲む

$ egrep [option] 'regex' file1 file2...

Page 10: 正規表現 入門

郵便番号 • テキストから郵便番号を取得したい $ egrep '[0-9]{3}-?[0-9]{4}' file01 • 実際に使用されているのは1000万の内14万程度 • 判別するには何らかのvalidatorが必要 • Number::ZipCode::JPを使いましょう(投げや

り)

Page 11: 正規表現 入門

メタ文字 • 次のページから正規表現のメタ文字についての

解説 • 正規表現を文字通りに解釈する癖を付けよう • 本質的な理解に繋がる • 例,文字通りの解釈,わかりやすい解釈と表記

(一部除く) • また,...は…と同じ扱いとする

Page 12: 正規表現 入門

行頭マッチ • ^ • 文字列の先頭と一致

• '^cat' • 行頭があって,その次がc,その次がa,その次

がtになっている行にマッチする • 行頭がcatになっている行にマッチする

Page 13: 正規表現 入門

行末マッチ • $ • 文字列の末尾と一致

• 'cat$' • cがあって,その次がa,その次がt,その次が行

末になっている行にマッチする • 行末がcatになっている行にマッチする

Page 14: 正規表現 入門

行頭と行末 • '^$' • 行頭の次に行末が続くならマッチする • 空行

• '^cat$' • 行頭の次にc,a,tと続きその次に行末が続くな

らマッチする • catだけの行

Page 15: 正規表現 入門

行頭と行末 • '^' • 行頭があるならマッチする • 全ての行にマッチする

• '$' • 行末があるならマッチする • 全ての行にマッチする

Page 16: 正規表現 入門

文字クラス • [...] • 複数の文字のどれか1つにマッチする

• 'gr[ae]y' • gの次がr,その次がaかeで,その次がyなら

マッチする • grayとgreyにマッチする

• gray(主に米),grey(主に英)

Page 17: 正規表現 入門

文字クラス • -を使って範囲を示すことができる • '[0123456789]' = '[0-9]' • '[ABCDE...Z]' = '[A-Z]' • '[abcde...z]' = '[a-z]' • '[012...9ABCDEFabcdef]' = '[0-9A-Fa-f]'

• 文字クラス内ではメタ文字が異なる • 人名として'[Ss]mith'とした場合blacksmithな

どの関係ないものにもマッチすることに注意

Page 18: 正規表現 入門

否定文字クラス • [^...] • 含まれていない任意の文字にマッチする • 含まれていなければマッチではないことに注意

(そうだと空行にもマッチしてしまう)

• '[^0-9]' • 0か1か2か…9が入っていない任意の文字に

マッチする • 数字が入っていない任意の文字にマッチする

Page 19: 正規表現 入門

egrepの仕様 • $ egrep 'A[^B]' file01 • TAにはマッチしない • Aの次には改行文字が続く • egrepは仕様で正規表現の前に改行文字を取り

除く

Page 20: 正規表現 入門

任意の1文字にマッチ • . • 任意の1文字にマッチする

• 'A.B' • Aの次に何かしらの文字があって,その次にBが

ある

Page 21: 正規表現 入門

部分のどれかにマッチ • | • 'or'の意.複数の正規表現を組合せてどれかと

マッチする正規表現にする

• 'gr[ae]y' = 'gr(a|e)y' = 'gray|grey' • 'gra|ey'はgraとeyにマッチする • '[a|e]'ではa,|,eにマッチする

Page 22: 正規表現 入門

大文字小文字の無視 • -iオプション • egrepのオプション • 他の言語の正規表現でもiは大文字小文字を無視

するオプションとなる

$ egrep -i 'from|to' file = $ egrep '[Ff][Rr][Oo][Mm]|[Tt][Oo]' file

Page 23: 正規表現 入門

単語 • ¥<string¥> • egrepでは精々文字と数字の並びを認識する

• the quick brown_ fox's $190.3? $!?. • 赤字が単語と認識される部分である

Page 24: 正規表現 入門

量指定子:オプション • ? • colou?rはc, o, l, o, u?, rならマッチ • u?は常に成功する • 直前のサブ式(要素)と0回または1回マッチ

• 'colou?r' • colorとcolourにマッチ

• '1st|1' = '1(st)?'

Page 25: 正規表現 入門

量指定子:繰り返し • + • 直前のサブ式と1回以上マッチ

• * • 直前のサブ式と0回以上マッチ

• 'A+' = 'AA*' • 'AA*' ≠ '(AA)*'

Page 26: 正規表現 入門

エスケープ • ¥char • メタ文字をリテラルとして扱う

• '¥.' • .にマッチする

Page 27: 正規表現 入門

egrep - 正規表現 ^ 行頭マッチ $ 行末マッチ . 任意の1文字にマッチ [ABC] A, B, Cのいずれかにマッチ [^ABC] A, B, Cいずれでもないものにマッチ [A-Z] A~Zのいずれかにマッチ [^A-Z] A~Zのいずれでもないものにマッチ c1|c2 c1, c2のいずれかにマッチ

Page 28: 正規表現 入門

egrep - 正規表現 + 1回以上の繰り返し * 0回以上の繰り返し ? 0回以上1回以下の繰り返し {n} n回繰り返し {n,} n回以上繰り返し {,m} m回以下繰り返し {n,m} n回以上m回以下繰り返し () 範囲の限定 ¥char charをエスケープ

Page 29: 正規表現 入門

1. まとめ • 正規表現は非常に便利なツールである • egrepは簡易に検索を行うことができるが正規

表現としては弱い(表で全部ではない,はず) • 正規表現の基礎は大体こんな感じ • 方言が豊富なので簡単に話せない(つらい)

• 正規表現で遊びたければPerlを使おう!

Page 30: 正規表現 入門

2. 実用例 • 注意:Perl5とかの話

Page 31: 正規表現 入門

テキストエディタで置換 • notepadでは正規表現による置換はできない • notepad++とかgedit(プラグイン)だとか秀

丸エディタだとかの(まともな)テキストエディタにはあるので使おう

Page 32: 正規表現 入門

Perlで正規表現 • マッチ(mは省略可) • m/regex/mods • 置換 • s/regex/replacement/mods

• パターンマッチ演算子 • value =~ /regex/mods • マッチすれば1,しなければ"" • if文で特定の奴のみ……とか

Page 33: 正規表現 入門

修飾子(mods) • /i 大文字小文字無視 • /x フリーフォーマット(文字クラス外の空白無

視) • /g 繰り返しマッチ

Page 34: 正規表現 入門

後方参照 • 後方参照自体はただの正規表現 • カッコでグループ化した文字列を後に参照

• ¥<(.*?)>.*?</¥1>¥ • <a>sdad</a>や<list>dfasj</list>にマッチ

Page 35: 正規表現 入門

特殊変数 • 正規表現外で参照

if($str =~ /(.*)?/) { print $1; # ()の中身 }

Page 36: 正規表現 入門

Perlワンライナー $ perl [option] '[perlScript]' file01 • -e:文字列をスクリプトとして実行 • -n:1行ずつ処理 • -p:出力 • -l:強制改行 • -i:出力先を入力ファイル自身にする

Page 37: 正規表現 入門

バックアップ $ perl -i'*.back' -e '[perlScript]' file

Page 38: 正規表現 入門

一括置換 $ find . -type f -print0 | xargs -0 sed -i -e 's/foo/bar/g' gitにも対応させたい $ git grep -l 'foo' | xargs -0 sed -i -e 's/foo/bar/g' $ git ls-files -z | xargs -0 sed -i -e 's/foo/bar/g' findを使うと.gitを巻き込むっぽい

Page 39: 正規表現 入門

3. 有限オートマトン • モデルの一つ • 有限個の”状態”の内1つの状態を取り,条件等に

より他の状態に移動することを”遷移”という • 様々な分野に応用されている

• 正規表現エンジンにも関わるので紹介

• 深夜テンションで作ってたのでこのへんからお

かしくなりだした

Page 40: 正規表現 入門

オートマトンとは • 自動羊肉

Page 41: 正規表現 入門

オートマトンとは • automaton:自動(制御)装置 • 自動で動く機械を”状態”と”遷移”という考え方で

理解し設計に応用しようというもの • 入力の最後で決められた状態(つまり成功)を

”受容”や”受理” • (状態と遷移の概念さえ理解すればオートマト

ンの基礎的な話は終わってしまう(!))

Page 42: 正規表現 入門

有限オートマトンの分類 • 更に2種類に分類できる • 決定性有限オートマトン

(Deterministic Finite Automaton:DFA) • 非決定性有限オートマトン

(Nondeterministic Finite Automaton:NFA) • 説明は後に譲る

Page 43: 正規表現 入門

状態 • 例えば健康状態(良好,普通,不調) • 例えば気温(30℃,29℃,28℃) • 例えば自販機に入れた金額(100円,110円)

• 感覚的に理解してしまえば良い,とりあえず状

態である

Page 44: 正規表現 入門

遷移 • 良好→普通 • 29℃→30℃,29℃→28℃ • 100円→110円

• イベントや条件によってある状態から別の状態

に移動することを遷移という

Page 45: 正規表現 入門

状態遷移図 • 有限オートマトンをグラフィカルにしたもの • DFA,NFA,ムーア・マシンで用いる状態遷移

図とミーリ・マシンで用いる状態遷移図がある • 0を出力するアイドル状態からスタートボタン

を押すとLEDが”点灯し1を出力”,以降はスイッチの入力によって”消灯し0を出力”,”点灯し1を出力”を繰り返すもので状態遷移図を描く

• 状態と遷移が定義されたものを状態機械という

• 正規表現に関わるのはムーア・マシンのもののみなのでミーリ・マシンのものについては割愛

Page 46: 正規表現 入門

ムーア・マシン

アイドル 0

スタート

LED点灯1

LED消灯 0

スイッチ

スイッチ

Page 47: 正規表現 入門

言語 • 文字列の集合を言語という(ここで言う集合は

数学的な集合) • つまり文字列が言語に所属するか判定可能 • 英語は複雑なので状態機械を用いる • 次に例を示す

Page 48: 正規表現 入門

状態機械の例 • abcという文字列からなる言語 • {abc} • abcとxyzという文字列からなる言語 • {abc, xyz} • 3文字以上のaからなる全ての文字列 • {aaa, aaaa, aaaaa...} • abもしくはcdが2回以上繰り返される文字列か

らなる言語 • {abab, abcd, cdcdcd...}

Page 49: 正規表現 入門

正規言語 • 大体先ほどの操作で得られる言語を正規言語と

いう.正確には以下の性質を満たすものである • DFAによって受理可能 • NFAによって受理可能 • 正規表現で記述可能 • 正規文法から生成可能 • 読み取り専用チューリングマシンで受理可能 • 以上5項目は全て等価である

Page 50: 正規表現 入門

特殊な文字列 • 空文字列 • 長さが0の文字列 • λやεで表記.本スライドではεで統一 • 空言語(くうげんご) • 数学的な集合の空集合に相当 • φ

• 空文字列からなる言語を{ε},空言語からなる

言語をφ

Page 51: 正規表現 入門

DFA,NFA • 決定性とは遷移先が必ず1つに決まっているこ

とを意味する • (決定的,非決定的という表記もする) • つまりDFAでは各状態において遷移先は1つに

決まっているが,NFAではそうではない • またNFAで実現可能なものはDFAで実現可能

(受理能力に差はない)

Page 52: 正規表現 入門

DFA,NFA

A

A ADFA

NFAA

Page 53: 正規表現 入門

DFA - 判定方法 • まずは判定方法を決める必要があるが,以下の

通りとする • 文字列の先頭から1文字ずつ調べ,その文字に

よって状態を遷移させる • 文字列が終わったとき予め決めておいた状態な

らばこの言語に所属していると判定する

• もう少し詳細に次に記す

Page 54: 正規表現 入門

DFA - 判定方法 • 遷移の条件は文字である • 開始状態を1つ決める(ここから始める).最

初の矢印が記す • 終了状態を決める.複数でも良いし,開始状態

と重なっても良い.二重丸で表記

• また,それをオートマトンと呼ぶ

• 以下に手順を記す

Page 55: 正規表現 入門

DFA - 手順 1. 文字列を取得する 2. オートマトンを開始状態から始める 3. 文字列の先頭から1文字ずつ取り出す 4. 取り出した文字によって遷移 5. 繰り返し 6. 文字列の末尾に到達したとき終了状態ならば言

語に所属している

Page 56: 正規表現 入門

DFA - 言語に所属しない条件 • 終了状態で終了しない(通りすぎても駄目) • 遷移先が示されない

• ABCという文字列に対し受理する,しないもの

の状態遷移図を次に描く

Page 57: 正規表現 入門

DFA - 判定

A B

C

A B C受理する

受理しないA B C

Page 58: 正規表現 入門

NFA - 手順 • 基本はDFAに準拠する 1. 遷移先が複数ある際それぞれに複製したものを

送る 2. 同時にDFAと同様に手順 3. 1つでも終了状態になったものがあれば言語に

所属

• ABCという文字列に対し受理する,しないものの状態遷移図を次に描く

Page 59: 正規表現 入門

NFA - 判定

A B

A

受理する

受理しない

B

C

A B

A B

C

Page 60: 正規表現 入門

NFAの意義 • 先に目的の言語を考えてからそれを受理する

オートマトンを構成しようとした際,NFAがあれば機械的に構成可能である. つまり正規表現からDFAを構成とか

• DFAよりも状態数が少なくなるものがある

Page 61: 正規表現 入門

ε-NFA • 空文字列に対しての状態遷移が存在する可能性

がある(存在しなくても良い). • 言語の表現能力がNFAに等しい.つまりDFAに

等しい.

Page 62: 正規表現 入門

ε-NFA - 手順 1. 1文字取り出す 2. 取り出した文字によって遷移する前に次の状態

に移る 3. 文字によって遷移

• 2の動作をε遷移という.これも非決定性

• ACという文字列に対し受理する,しないものの

状態遷移図を次に描く

Page 63: 正規表現 入門

ε-NFA - 判定

A B

A

受理する

受理しない

B

C

A ε

A B

C

Page 64: 正規表現 入門

ε-NFAの意義 • 正規表現から直接DFAに変換するのは難しい • 正規表現→ε-NFA→NFA→DFAと変換する

Page 65: 正規表現 入門

4. 正規表現の動作原理 • 2で記したものを踏まえて正規表現の動作を簡

潔に記す • あくまで根幹の大まかな動作であり,動作全て

を表したわけではないことに注意

Page 66: 正規表現 入門

正規表現エンジン • 3(2)種類ある • NFA(従来型NFA)(正規表現主導) • POSIX NFA • DFA(テキスト主導) • NFA:.NET言語,PHP,Ruby,Perl,

Python,GNU Emacs,sed,vi,ほとんどのgrep

• DFA:awk,lex,flex,ほとんどのegrep • NFAの方が多い

Page 67: 正規表現 入門

POSIX NFA • DFAとNFAの開発が進みやたらとでかくなって

しまったところに現れたのがPOSIX標準 • メタ文字や機能,結果の明確化 • POSIX準拠:POSIX標準準拠の正規表現エンジ

ンに期待して良い動作 • POSIX準拠にした結果少々ややこしくなったも

のも.遅くもなった

Page 68: 正規表現 入門

NFA or others • 'nfa|nfa not' • nfa notに適用する • nfaにしかマッチしないならNFA(従来型NFA)

Page 69: 正規表現 入門

POSIX NFA or DFA • 'X(.+)+X' • '=XX====================='に適用 • 時間がかかればNFA(POSIX NFA) • すぐに終わればDFA • オーバーフローなどの警告がでたらNFA

Page 70: 正規表現 入門

原則 1. 最初にマッチしたものが優先される 2. 標準の量指定子は欲張りである

• 欲張りとは最大のテキストでマッチしようとす

る,という意味である

• a bad dabに'a.*b'を適用すると全体にマッチ(最初にマッチしたものであり欲張りである)

Page 71: 正規表現 入門

最適化について • ここでは最適化については考慮しない • まず文字列の先頭でマッチしない場合次の位地,

次の位地と進めて試行するが'^.*'などの正規表現では無意味である

• 最適化によりエンジンで判断できるがここでは無視する

Page 72: 正規表現 入門

NFA(正規表現主導) • tonightという文字列 • 'to(nite|knight|night)'という正規表現 • 評価の順はt,o,(nite),(knight),(night)で

ある • 1つずつ順に正規表現を試していく

Page 73: 正規表現 入門

バックトラック • NFAの根幹はバックトラックである • 少なくともマッチが見つかるまで必要な限り全

ての順列を試す • 'to(nite|knight|night)'に対しtoniまでいっ

て次が不一致であればtoまで戻りtokn……と試していく

Page 74: 正規表現 入門

DFA(テキスト主導) • tonightという文字列 • 'to(nite|knight|night)'という正規表現 • t,oと評価したあとnを評価する.この時点で

一致するのは(nite)か(night)である. • (knight)はnを評価した時点でマッチしないこと

がわかるので除外される • 並列に処理していく感じ • 決定的である.高々一回しか評価されない

Page 75: 正規表現 入門

DFAとNFAの比較 • DFAは並列に処理するので高速であり安定して

いる.但し表現の幅は狭い • NFAは順に正規表現を評価するため正規表現の

書き方によって仕事量が増大する • バックトラックを根幹としている.最小量指定

子など様々な表現ができる

• 「NFAは複製するんだしNFAが並列に処理するんじゃないの?」←正規表現の動作を追うとわかる

Page 76: 正規表現 入門

POSIX NFAと従来型NFA • POSIX NFAは最長のマッチを返す • 最左最長原則:同じ位置から複数マッチが始ま

れば最も長いテキストにマッチするものを返す • 効率が問題になってくる • 従来型NFAはかなり幅広い表現が可能である.

正規表現エンジンの中で最も表現力が高い

Page 77: 正規表現 入門

Tcl • NFAエンジンのような表現をもちPOSIX NFA

の最左最長原則をサポートする.且つNFAエンジンの問題を受けない

• Henry Spencer(初期の正規表現の開発と普及に関する偉大な人物)によるもの

Page 78: 正規表現 入門

5. まとめ • 正規表現つおい • 少し覚えればかなり使える • Perlのワンライナーで一括置換とかやって楽に

• 正規表現の話が半分ぐらいしかない気がするの

で土下座 • というか入門じゃないので土下座 • 結局対象者が不透明なので土下座

Page 79: 正規表現 入門

御清聴ありがとうございました