## Perl ワンライナー入門
#### 講師:USP友の会 鳥海秀一
### Perlワンライナー入門(全2回)
* 第1回:Perlワンライナー入門
* 第2回:Perl正規表現入門
### Perlワンライナー入門(全3回)
* 第1回:Perlワンライナー入門
* 第2回:Perl正規表現入門 その1
* 第3回:Perl正規表現入門 その2
### 第1回:Perlワンライナー入門
#### ワンライナーを支援するPerlの機能
* 未定義の変数が使用可能
* ダイヤモンド演算子
* 豊富な特殊変数
* 豊富な起動オプション
### 第2回:Perl正規表現入門 その1
#### ワンライナーを支援するPerlの機能
* 強力な正規表現
* 変数展開、変換エスケープ
* 置換演算子
* パターン修飾子
* プログレッシブマッチ
* 文字エイリアス、文字クラス
* アンカー
* 量指定子(最短マッチ)
* キャプチャとクラスタ化
* ルックアラウンドアサーション
* qr//クォート正規表現演算子
### 第3回:Perl正規表現入門 その2
* 強力な正規表現
* 非バックトラックサブパターン
* プログラムパターン
* マッチ時コード評価
* マッチ時パターン展開
* 集大成
講師: 鳥海秀一
- Perlプログラマ歴:6ヶ月
- 変態Perlプログラマ歴:3ヶ月
こんな講師でごめんなさい
### 講義の前提
* Perlのワンライナーを記述する基本的な知識がある
* Perlの正規表現の基本的な知識がある
### 参考書
* プログラミングPerl(オライリー・ジャパン)
* 詳説 正規表現(オライリー・ジャパン)
### まずはPerlの正規表現を使った変態ワンランナーを見ていただきます
### 問題1
* 標準入力から与えられた文字列の中の2文字の部分文字列を全て出力するプログラムを書きなさい
### まともなPerlプログラマの解答例
* echo abcdef | perl -lne 'while(/../g){print $&;--pos}'
### 変態Perlプログラマの解答例
* echo abcdef | perl -lne '/..(?{print$&})(?!)/'
### 問題2
* 響け!ユーフォニアム問題を解きなさい
### まともなPerlプログラマの解答例
* echo 響け!ユーフォニアム | perl -C -lne '$_ x=11;print for /(.{10})./g'
### 変態Perlプログラマの解答例
* echo 響け!ユーフォニアム | perl -C -lne '$_ x=2;/.{10}(?{print$&})(?=.$)/'
### Perlの正規表現の特徴
* 速度が遅くなりやすい
### すぐ終わるPerlの正規表現
* echo aaaaaaaaaaaaaaaaaaaab | perl -lne 'print if /a\*a\*a\*a\*a\*a\*a\*a\*[bc]/'
### すぐには終わらないPerlの正規表現
* echo aaaaaaaaaaaaaaaaaaaa | perl -lne 'print if /a\*a\*a\*a\*a\*a\*a\*a\*[bc]/'
### Awkだとすぐに終わる
* echo aaaaaaaaaaaaaaaaaaaa | awk '/a\*a\*a\*a\*a\*a\*a\*a\*[bc]/'
### 問題
* Awk と Perl では何が異なるのか?
* Perlの正規表現が遅いのはなぜか?
* Perlはその対策を持っていないのか?
### 問1
* Awk と Perl では何が異なるのか?
### 正規表現エンジンとは
* 正規表現を解釈し、パターンマッチを行うプログラムの部品のこと
* 根本的に異なる2つの方式がある
* DFA型エンジン
* NFA型エンジン
### DFA型正規表現エンジン
* 決定性有限オートマトンを元に正規表現の解釈とパターンマッチを行う
* 処理が早い
* メモリをたくさん消費する
* 拡張性に乏しい(例:後方参照の実装が困難)
* 昔のegrep、ほとんどのAwkが採用している
### NFA型正規表現エンジン
* 非決定性有限オートマトンを元に正規表現の解釈とパターンマッチを行う
* 処理が遅い
* メモリはあまり消費しない
* 拡張性に富んでいる
* grep、sed、Perl等ほとんどの処理系が採用している
### ちなみに
* GNU awkとGNU grepはハイブリッド型
* NFA型エンジンには以下の2つのタイプがある
* 従来型NFA - 最左最長・早い者勝ち
* POSIX NFA - 最左最長
### 問2
* Perlの正規表現が遅いのはなぜか?
### 答え
* NFA型エンジンはバックトラック法を用いてパターンマッチを行なうから
### バックトラック法とは
* すべての場合を調べないと正解が得られないような複雑な問題について、ある分岐点に来たときに一方を選択し進んでいき、それが間違いだと判断した場合に、最後に分岐した地点まで戻り、もう一方の方向へ進むということを何度も繰り返し、正解を導き出す方法(ASCII.jpデジタル用語辞典より)
### バックトラックを行う正規表現例
* echo abcdef | perl -lne 'print $1 if /(.*)./'
### バックトラックを可視化する
* echo abc | perl -Mre=debug -lne 'print $1 if /.*./'
* echo abc | perl -Mre=debug -lne 'print $1 if /.*../'
### マッチ時コード評価
* (?{CODE})という形をした正規表現
* マッチは行わない
* 常に成功する幅ゼロのアサーション
* 副作用によりCODEの評価を行う
### マッチ時コード評価の例
* echo abcdef | perl -lne '/.*(?{print "hi")}/'
* echo abcdef | perl -lne '/.*(?{print "hi")}./'
### 遅い正規表現の評価回数を確認
* echo aaaaaaaaaaaaaaaaaaaa | perl -lne '$i=0;print if /a\*a\*a\*a\*a\*a\*a\*a\*(?{$i++})[bc]/;print $i'
### 正規表現(?!)
* 常に失敗する先読みアサーション
* 最適化の対象外となっているもよう
### 変態正規表現プログラム
* echo abcdef | perl -lne '/..(?{print$&})(?!)/'
* echo 響け!ユーフォニアム | perl -C -lne '$_ x=2;/.{10}(?{print$&})(?=.$)/'
### 問3
* Perlは正規表現が遅くならないような対策を持っていないのか?
### 非バックトラックサブパターン
* (?>PATTERN)という形をした正規表現
* 別名はアトミックグループ
* PATTERNがマッチを見つけると決してバックトラックしない
* バックトラックしない点以外は(?:PATTERN)と同じ動作をする
* PATTERNに量指定子や選択肢が含まれていないと(?:PATTERN)と同じ
### アトミックグループの例
* echo aaaaaaaaaaaaaaaaaaaa | perl -lne 'print if /(?>a\*a\*a\*a\*a\*a\*a\*a\*)[bc]/'
### マッチ時パターン展開
* (??{CODE})という形をした正規表現
* CODEの評価結果をパターンとして採用する
### 回文にマッチするパターン
* /^(.+).?(??{reverse $1})$/
### 解説しきれなかった機能
* split関数
* その他いろいろ
### Perlの正規表現の特徴
* 拡張正規表現を上回る豊富な表現力をもつ
* もともと正規表現は正規文法というクラスに属する文法を記述する手段
* Perlの正規表現は正規文法のクラスに収まらない文法も記述可能
### これまでの知識を使えば正規文法クラスを超えられます
### 課題
* 入れ子のブレスで囲まれた文字列にマッチする正規表現を書きなさい
### 課題で使う主な機能
* qr演算子
* マッチ時パターン展開
* アトミックグループ
### 解答例
* $b=qr/{(?:(?>[^{}]+)|(??{$b}))*}/
### 皆さんへの指令
* 先ほどの解答例を使って、第28回シェル芸勉強会のQ3を攻略してください
#### この午前の部の勉強会でやりたかったこと
* Perlはシェル芸の仲間であることを宣言したかった
* 第28回シェル芸勉強会のQ3を攻略したかった