660 likes | 816 Views
s/ Perl5 Regular Expression / Perl6 Regex and Rules /mixes;. 竹迫 良範. 謝罪. 今日は真面目な プレゼンです m(_ _)m. はじめに. 自己紹介. My Name is 竹迫良範 Yoshinori TAKESAKO Perl との関係 1997 Perl と出会う 2003 mod_perl C10K Problem 2005 ppencode Joined CybozuLabs, Inc. ※ モヒカン族では ありません.
E N D
s/ Perl5 Regular Expression / Perl6 Regex and Rules /mixes; 竹迫 良範
謝罪 今日は真面目な プレゼンです m(_ _)m
自己紹介 • My Name is • 竹迫良範 • Yoshinori TAKESAKO • Perlとの関係 • 1997 • Perlと出会う • 2003 • mod_perl C10K Problem • 2005 • ppencode • Joined CybozuLabs, Inc. ※モヒカン族では ありません http://namazu.org/~takesako/ http://labs.cybozu.co.jp/blog/takesako/
My first computer
いきなり32bit世代 - F-BASIC 386 Compiler - x86 Assembler - LSI C-86試食版(DOS) ゲームばっかり作って遊んでました
広島市立大学 情報科学部 1995年
C, X11(Xlib), UNIX Network Programming • Require • X Window System, Version 11 Release 5 ~ • OS • Linux 2.0.17 • SunOS Release 4.1.3 • Solaris 2.1 • IRIX Release 5.3 • Machines • Sun SPARC station LX • Sun SPARC station 5 • Gateway 2000 HandBook i486 やっぱりゲーム作ってました(汗)
当時の流行 Java ~
My Programming History @Home @school @office Java ? BASIC x86 C Perl Portability FM TOWNS 限定された独自 アーキテクチャ UNIX Network X11 Windows HP-UX Linux
現在に至る • Shibuya Perl Mongers リーダー交代式 • Basokiya 2006 Cup いまここ
Perl 6 Today yesterday
Today’s Perl 6 Talks • 09:30- Dan “Fred” Kogai • ふつうの Perl 6 入門 • An Ordinary Perl6 Guide • 13:15- Yoshinori Takesako • s/ Perl5 Regular Expression / Perl6 Regex and Rules /mixes; • 正規表現にフォーカスした Perl 6 入門
正規表現 Perl 5 Perl 6
Perl5 正規表現 Perl6 Regex で変わるもの • 1. 基本パターン • 繰り返し *+? と選択 | • 2. マッチ演算子 • 文字列のパターンマッチ m// • スマートマッチ演算子 ~~ • 文字列の置換 s/// • 3. 修飾子 • 複数行モード/m 修飾子の廃止 • 文字列の先頭「\A」末尾「\z」の廃止 • スペースとコメントが自由に挿入できるモード/x がデフォルトに • スペースのマッチ • 単一行モード/s の廃止 • /e 修飾子の廃止 • 新しい修飾子の書き方 • 空白マッチ修飾子:w
Perl5 正規表現 Perl6 Regex で変わるもの • 4. キャプチャ • キャプチャ括弧(…)と後方参照 • キャプチャを伴わない括弧 […] • 5. メタキャラクタ • 文字クラスの定義 <[a-z]> • 定義済み文字クラスの参照 <class> • 変数展開 <$var> • 文字列 <'string'> のリテラル展開 • 文字列配列 @strings のリテラル展開
Perl5 正規表現 Perl6 Regex の未来 • 6. クロージャ • コードの実行 {code} • マッチ失敗 {fail} • 繰り返し範囲 **{n..m} • 7. ルール • rule • grammar • 8. Perl5互換の正規表現 • ご安心ください
繰り返し *+? と選択 | Perl 6 Perl 5 /x*/ # xが0個以上繰り返し /y+/ # yが1個以上繰り返し /z?/ # zが0個以上1個以下 /foo|bar/ # fooまたはbar /x*/ # == Perl 5 /y+/ # == Perl 5 /z?/ # == Perl 5 /foo|bar/ # == Perl 5 $_ = "aaa bbb ccc foo moo zoo"; if (/aaax*/) { print "ok\n" } if (/b+/) { print "ok\n" } if (/cccc?/) { print "ok\n" } if (/foo|bar|baz/) { print "ok\n" } $_ = "aaa bbb ccc foo moo zoo"; if /aaax*/ { say "ok" } if /b+/ { say "ok" } if /cccc?/ { say "ok" } if /foo|bar|baz/ { say "ok" }
文字列のパターンマッチ m// Perl 6 Perl 5 /pattern/ m/pattern/ m{pattern} qr/pattern/ /pattern/ m/pattern/ m{pattern} rx/pattern/ または regex{pattern} $_ = "This is a pen."; if (/This/) { print "ok\n" } if (m/pen/) { print "ok\n" } if (m{pen}) { print "ok\n" } unless (/not match/) { print "ok\n" } if ($_ =~ qr/pen/) { print "ok\n" } $_ = "This is a pen."; if /This/ { say "ok" } if m/pen/ { say "ok" } if m{pen} { say "ok" } unless /not match/ { say "ok" } if ($_ ~~ rx/pen/) { say "ok" } ※ただし、Pugs6.2.13 では「m##」や「m()」の記号を使用するとエラーになります
スマートマッチ演算子 ~~ Perl 6 Perl 5 $str ~~ /pattern/ $str !~~ /pattern/ /pattern/ ~~ $str /pattern/ !~~ $str $str =~ /pattern/ $str !~ /pattern/ my $str = "This is a pen."; if ($str =~ /This/) { print "ok\n" } if ($str =~ m/pen/) { print "ok\n" } ## (m/pen/ =~ $str) とは書けない if ($str !~ /not match/) { print "ok\n" } unless ($str ~~ /not match/) { print "ok\n" } my $str = "This is a pen."; if $str ~~ /This/ { say "ok" } if $str ~~ m/pen/ { say "ok" } if m/pen/ ~~ $str { say "ok" } if $str !~~ /not match/ { say "ok" } unless $str ~~ /not match/ { say "ok" }
文字列の置換 s/// Perl 6 Perl 5 s/pattern/replace/ s{pattern}{replace} s/pattern/replace/ s{pattern}{replace} s{pattern} = 'replace' my $str = "This is a pen."; if ($str =~ s/pen/book/) { if ($str eq "This is a book.") { print "ok\n" } } if ($str =~ s{book}{notebook}) { if ($str eq "This is a notebook.") { print "ok\n" } } my $str = "This is a pen."; if $str ~~ s/pen/book/ { if $str eq "This is a book." { say "ok" } } if $str ~~ s{book} = 'notebook' { if $str eq "This is a notebook." { say "ok" } } ※Rubyでは文字列の置換を「s[/pattern/] = 'replace'」と書くことができる。
複数行モード/m 修飾子の廃止 Perl 6 Perl 5 /^^pattern$$/ /^pattern$/m 正規表現の修飾子/mで「^」と「$」のマッチ規則が変わる my $lines = "aaa\nbbb\nccc\n"; if ($lines =~ /^b/m) { print "ok\n" } if ($lines =~ /bb$/m) { print "ok\n" } if ($lines =~ /^bbb$/m) { print "ok\n"; } my $lines = "aaa\nbbb\nccc\n"; if $lines ~~ /^^b/ { say "ok" } if $lines ~~ /bb$$/ { say "ok" } if $lines ~~ /^^bbb$$/ { say "ok" ; }
文字列の先頭「\A」末尾「\z」の廃止 Perl 6 Perl 5 /^pattern$/ /\Apattern\z/ 複数行モード/m に影響しないアンカー記号「\A」「\z」 my $str = "abracadabra"; if ($str =~ /\Aabra/) { print "ok\n" } if ($str =~ /abra\z/) { print "ok\n" } if ($str =~ /\Aabracadabra\z/) { print "ok\n" ; } my $str = "abracadabra"; if $str ~~ /^abra/ { say "ok" } if $str ~~ /abra$/ { say "ok" } if $str ~~ /^abracadabra$/ { say "ok" ; }
スペースとコメントが自由に挿入できるモード/x がデフォルトに Perl 6 Perl 5 / pattern1 # コメントをここに書く pattern2 pattern3 /x / pattern1 # コメントをここに書く pattern2 pattern3 / my $str = "abracadabra"; if ( $str ~~ / abra # アブラ ca # カ d abra # ダブラ / # 正規表現の終了 ) { say "ok" } if $str ~~ / abra cad abra / { say "ok" } my $str = "abracadabra"; if ( $str =~ / abra # アブラ ca # カ d abra # ダブラ /x # 正規表現の終了 ) { print "ok\n" } if ( $str =~ / abra cad abra /x ) { print "ok\n" }
スペースのマッチ Perl 6 Perl 5 /\ /x /\Q \E/x /[ \t\r\n]/x /[ \t\r\n]+/x /\ / /<' '>/ /<space>/ /<ws>/ my $str = "This is\ta \n pen ."; if $str ~~ / This \ is / { say "ok" } if $str ~~ / This <' '> is / { say "ok" } if $str ~~ / is <space> a / { say "ok" } if $str ~~ / a <ws> pen / { say "ok" } my $str = "This is\ta \n pen."; if ($str =~ / This \ is /x) { print "ok\n" } if ($str =~ / This \Q \E is /x) { print "ok\n" } if ($str =~ / is [ \t\r\n] a /x) { print "ok\n" } if ($str =~ / a [ \t\r\n]+ pen /x) { print "ok\n" }
単一行モード/s の廃止 Perl 6 Perl 5 /./ # 改行を含むどんな文字にもマッチ /\N/ # 改行以外のどんな文字にもマッチ /\n/ # どんな端末の改行にもマッチ /./s # どんな文字にもマッチ(改行を含む) /./ # どんな文字にもマッチ(改行は除く) /[\x0D\x0A]|\x0D\x0A/ # どんな端末の改行 my $c = '/*********************** * This is a C comment * ***********************/ #include <stdio.h> /* first */ main() { printf("C"); }'; if ($c =~ m/(\/\*.+?\*\/)/) { if ($1 eq "/* first */") { print "ok\n" } } if ($c =~ m/(\/\*.+?\*\/)/s) { my $lines = $1; if ($lines =~ /comment/) { print "ok\n" } } my $c = '/*********************** * This is a C comment * ***********************/ #include <stdio.h> /* first */ main() { printf("C"); }'; if $c ~~ m{( \/\* \N+? \*\/ )} { if $0 eq "/* first */" { say "ok" } } if $c ~~ m{( \/\* [.|\n]+? \*\/ )} { my $lines = $0; if $lines ~~ /comment/ { say "ok" } }
/e 修飾子の廃止 Perl 6 Perl 5 s/pattern/{code}/ s/pattern/code/e sub cm2inch { my ($cm) = @_; sprintf('%.01f-inch', $cm / 6.5); } my $floppy = "3.5-inch FDD"; if ($floppy =~ s/(\d+\.\d+)-inch/{ sprintf('%.02f-cm', $1 * 6.5) }/ex) { if ($floppy eq "22.75-cm FDD") { print "ok\n" } if ($floppy =~ s/(\d+\.\d+)-cm/{ &cm2inch($1) }/ex) { if ($floppy eq "3.5-inch FDD") { print "ok\n" } } } sub cm2inch($cm) { sprintf('%.01f-inch', $cm / 6.5); } my $floppy = "3.5-inch FDD"; if $floppy ~~ s/(\d+\.\d+)-inch/{ sprintf('%.02f-cm', $0 * 6.5) }/ { if $floppy eq "22.75-cm FDD" { say "ok" } if $floppy ~~ s/(\d+\.\d+)-cm/{ &cm2inch($0) }/ { if $floppy eq "3.5-inch FDD" { say "ok" } } } Cf. Acme::Hyde(単位変換) on CPAN
新しい修飾子の書き方 Perl 6 Perl 5 m/pattern/i m/pattern/g s/pattern/replace/ig m:i/pattern/ m:e/pattern/ s:i:e/pattern/replace/ または m:ignorecase/pattern/ または m:each/pattern/ my $imas = "とかしつくして"; if ($imas =~ s/し/ち/g) { if ($imas eq "とかちつくちて") { print "ok\n"; } } my $imas = "とかしつくして"; if $imas ~~ s:g/し/ち/ { if $imas eq "とかちつくちて" { say "ok"; } }
空白マッチ修飾子:w Perl 6 Perl 5 m:w/foo bar/ m:w/ foo bar / m/foo\s+bar/ m/\s*foo\s+bar\s*/ Perl6 では、スペースとコメントが自由に挿入できるモード/x がデフォルトになったため 正規表現中にスペースを書いても無視されてしまう... whitespaceを有効にする空白マッチ修飾子:w my $str = "begin: foo bar \t baz \n end"; if ($str =~ m/(foo \s+ bar)/x) { if ($1 eq "foo bar") { print "ok\n" } } if ($str =~ m/(\s* foo \s+ bar \s*)/x) { if ($1 eq " foo bar \t ") { print "ok\n" } } my $str = "begin: foo bar \t baz \n end"; if $str ~~ m:w/(foo bar)/ { if $0 eq "foo bar" { say "ok" } } if $str ~~ m:w/( foo bar )/ { if $0 eq " foo bar \t " { say "ok" } }
キャプチャ括弧(…)と後方参照 Perl 6 Perl 5 (…),$0,$1,$2… (…),\1,\2,\3… 括弧(…)でキャプチャして、同じ正規表現内で後方参照する my $str = "abracadabra"; if ($str =~ /(a)br\1c/) { print "ok\n" } if ($str =~ /(ab)racad$1ra/) { print "ok\n" } if ($str =~ /(a)(b)r$1c$2d$2$2ra/) { print "ok\n" ; } if ($1 eq "a") { print "ok\n" } if ($2 eq "b") { print "ok\n" } my $str = "abracadabra"; if $str ~~ /(a)br$0c/ { say "ok" } if $str ~~ /(ab)racad$0ra/ { say "ok" } if $str ~~ /(a)(b)r$0c$0d$0$1ra/ { say "ok" ; } if ($0 eq "a") { say "ok" } if ($1 eq "b") { say "ok" } 【覚え方】 日本円\廃止 ドル$決済でゼロスタート (スクラップ&スクラップ)
キャプチャを伴わない括弧 […] Perl 6 Perl 5 [pattern] (?:pattern) my @domain = ( "shibuya.pm.org", "shibuya.pl" , "shibuyajs.org" , ); for (@domain) { if (/^(\w+)(?:\.|-)?(js|pm|pl)(?:.org)?$/) { print "Hello, $1 $2 !\n"; } } my @domain = ( "shibuya.pm.org", "shibuya.pl" , "shibuyajs.org" , ); for @domain { if /^(\w+) [\.|-]? (js|pm|pl) [.org]? $/ { say "Hello, $0 $1 !"; } } ドメイン名からコミュニティ名を判断し "Hello, shibuya pm !" と挨拶する
文字クラスの定義 <[a-z]> Perl 6 Perl 5 [abc] [a-z] [^xyz] [B-Y] <[abc]> <[a-z]> <-[xyz]> < <[A-Z]> - <[AZ]> > my @files = ("Jcode.pm", "Encode.pm", "jcode.pl"); for @files { if / ( [J|En|j] code \. p<[ml]> ) / { if $_ eq $0 { say "ok" } } } my @files = ("Jcode.pm", "Encode.pm", "jcode.pl"); foreach (@files) { if (/ ( (?:J|En|j) code \. p[ml]) /x ) { if ($_ eq $1) { print "ok\n" } } } "Jcode.pm", "Encode.pm", "jcode.pl" のどれにもマッチする正規表現
文字クラスの定義 <[a-z]> Perl 6 Perl 5 \x20 # 空白1文字 \s+ # 連続したスペース \. # ドット [[:digit:]] # [0-9] [[:upper:]] # [A-Z] [[:lower:]] # [a-z] [[:alpha:]] # [A-Za-z] [[:alnum:]] # [A-Za-z0-9] <space> # 空白1文字 <ws> # 連続したスペース <dot> # ドット ※<lt>, <gt> なども <digit> # 数字 <upper> # 英大文字 <lower> # 英小文字 <alpha> # アルファベット <alnum> # アルファベットと数字 $_ = "123 abc \t 456 ijk \t 789 XYZ"; if / (<digit>+) \ (<alpha>+) / { if $0 eq "123" && $1 eq "abc" { say "ok" } } if / (<alpha>+) <ws> (<digit>+) / { if $0 eq "abc" && $1 eq "456" { say "ok" } } $_ = "123 abc \t 456 ijk \t 789 XYZ"; if (/ ([0-9]+) \ ([A-Za-z]+) /x) { if ($1 eq "123" && $2 eq "abc") { print "ok\n" } } if (/ ([A-Za-z]+) \s+ ([0-9]+) /x) { if ($1 eq "abc" && $2 eq "456") { print "ok\n" } } ※Perl 6 Specs よりサンプル作成
変数展開 <$var> Perl 6 Perl 5 / <$var> / / $var /x my $var = "(This|That) is a (pen|book)"; my $text1 = "This is a pen"; my $text2 = "That is a book"; if ($text1 ~~ m:w/<$var>/) { say "ok"; } if ($text2 ~~ m:w/<$var>/) { say "ok"; } my $var = "(This|That) is a (pen|book)"; my $text1 = "This is a pen"; my $text2 = "That is a book"; if ($text1 =~ /$var/) { print "ok\n"; } if ($text2 =~ /$var/) { print "ok\n"; } ※Perl 6 Specs よりサンプル作成
文字列 <'string'> のリテラル展開 Perl 6 Perl 5 \Q$var\E \Qstring\E \$\Qstring\E $var <'string'> <'$string'> my $err = "Can't locate Boofy.pm in \@INC"; my $soozy = "Boofy.pm"; if $err ~~ /$soozy/ { say "ok"; } if $err ~~ /<'@INC'>/ { say "ok"; } my $err = "Can't locate Boofy.pm in \@INC"; my $soozy = "Boofy.pm"; if ($err =~ /\Q$soozy\E/x) { print "ok\n"; } if ($err =~ /\@INC/x) { print "ok\n"; } ※Perl 6 Specs よりサンプル作成
文字列配列 @str のリテラル展開 Perl 6 Perl 5 $target ~~ / (?: \Q$str[0]\E | \Q$str[1]\E | … ) /x $target ~~ / @str / my @str = ("orz", "OTL", "_|~|-O"); my $food = "pasta mista, peperini, capellini tagliati, orzi piccoli, stelline."; if $food ~~ / @str / { say "ok"; } my @str = ("orz", "OTL", "_|~|-O"); my $food = "pasta mista, peperini, capellini tagliati, orzi piccoli, stelline."; if ($food =~ /(?: \Q$str[0]\E | \Q$str[1]\E | \Q$str[2]\E )/x) { print "ok\n"; } ※Perl 6 Specs よりサンプル作成
コードの実行 {code} Perl 6 Perl 5 /pat{code}tern/ /pat<{retcode}>tern/ /pat(?{code})tern/ # 埋め込みコード /pat(??{retcode})tern/ # 動的正規表現 どこでもクロージャ{...} my $text = "pattern"; $text ~~ m/pat{say "ok"}tern/; if $text ~~ m/pat<{lc("TER")}>n/ { say "ok"; } my $text = "pattern"; $text =~ m/pat(?{print "ok\n"})tern/; if ($text =~ m/pat(??{lc("TER")})n/) { print "ok\n"; } ※Perl 6 Specs よりサンプル作成