スキップしてメイン コンテンツに移動

Perl 5 to 6 - 正規表現の逆襲

これはMoritz Lenz氏のWebサイトPerlgeek.deで公開されているブログ記事"Perl 5 to 6" Lesson 19 - Regexes strike backの日本語訳です。

原文はCreative Commons Attribution 3.0 Germanyに基づいて公開されています。

本エントリにはCreative Commons Attribution 3.0 Unportedを適用します。

Original text: Copyright© 2008-2010 Moritz Lenz

Japanese translation: Copyright© 2011 SATOH Koichi

NAME

"Perl 5 to 6" Lesson 19 - 正規表現の逆襲

SYNOPSIS

# 通常のマッチング:
if 'abc' ~~ m/../ {
    say $/;                 # ab
}

# 暗黙的な:sigspace修飾子を使ったマッチング
if 'ab cd ef'  ~~ mm/ (..) ** 2 / {
    say $1;                 # cd
}

# :sigspace修飾子を使った文字列置換
my $x = "abc     defg";
$x ~~ ss/c d/x y/;
say $x;                     # abx     yefg

DESCRIPTION

正規表現の基本はLesson 07で既に述べたので、役に立つ(が体系立っていない)内容をいくらか補足します。

マッチング

正規表現マッチングのためにグラマーを書かないといけない訳ではなく、昔ながらのm/.../はまだ動きます。 新しい兄弟分としてmm/.../形式があり、:sigspace修飾子を暗黙的に有効にします。これは正規表現中の空白を<.ws>ルールで置換するものだったことを思い出して下さい。

このルールのデフォルトは、2つの単語文字で囲まれている(つまりそれぞれが\wにマッチする)場合は\s+にマッチし、さもなくば\s*にマッチします。

文字列置換において:samespace修飾子は<ws>ルールにマッチした空白を保存します。 同様に:samecase及び短縮形の:ii(:iの親戚だからです)修飾子は大文字小文字の違いを保存します。

my $x = 'Abcd';
$x ~~ s:ii/^../foo/;
say $x;                     # Foocd
$x = 'ABC'
$x ~~ s:ii/^../foo/;
say $x                      # FOO

これはモジュールFooをすべてBarに改名したいけれど、例えば環境変数がすべて大文字で書かれているときに非常に便利です。:ii修飾子が大文字小文字の違いを自動で保存してくれます。

これは大文字か小文字かという情報を文字毎にコピーしますが、より頭の良いバージョンもあります; :sigspace(短縮形は:s)修飾子と一緒に使うと、大文字小文字のパターンをソース文字列から探します。 .lc.uc.lc.ucfirstuc.lcfirstlc.capitalize(Str.capitalizeは各単語の最初の文字を大文字にするメソッド)が認識されます。このようなパターンを見つけると置換後の文字列にも適用します。

my $x = 'The Quick Brown Fox';
$x ~~ s :s :ii /brown.*/perl 6 developer/;
# $xは'The Quick Perl 6 Developer'

選択肢

選択肢は相変わらず|で表現されますが、Perl5とは違った意味になります。 選択肢を順番にマッチングしていって最初にマッチしたものを取るのではなく、全選択肢を並列にマッチングして最長一致のものを取ります。

'aaaa' ~~ m/ a | aaa | aa /;
say $/                          # aaa

つまらない変更に見えるかも知れませんがこれは広範囲に影響し、また拡張性のあるグラマーにとって極めて重要です。 Perl6はグラマーを使って解析されるので、++$a++が2つのprefix:<+>トークンではなく1つのトークンとして解析されるのはこのためです。

順番にマッチングする古い方式は||で利用できます:

grammar Math::Expression {
    token value {
        | <number>
        | '(' 
          <expression> 
          [ ')' || { fail("Parenthesis not closed") } ]
    }
    ...
}

{ ... }はクロージャを実行し、その中でのfailの呼び出しは式を失敗させます。 この枝は前のマッチング(ここでは')')が失敗したときだけ呼び出されることが保証されているので、解析中に役立つエラーメッセージを出すのに使えます。

選択肢を書く方法は他にもあり、例えば配列を「展開」すると要素の選択肢としてマッチさせることができます:

$_ = '12 oranges';
my @fruits = <apple organge banana kiwi>;
if m:i:s/ (\d+) (@fruits)s? / {
    say "You've got $0 $1, I've got { $0 + 2 } of them. You lost.";
}

自動的に最長一致にマッチする選択肢の構築方法がもう1つあります: 多重正規表現です。 これはmulti token nameのように書かれるか、protoを使って次のように書かれます:

grammar Perl {
    ...
    proto token sigil { ... }
    token sigil:sym<$> { <sym> }
    token sigil:sym<@> { <sym> }
    token sigil:sym<%> { <sym> }
    ...
    token variable { <sigil> <twigil>? <identifier> }
}

この例はsigilという多重トークンを表しており、これはsymでパラメータ化されています。 短い名前、つまりsigilが使われた場合は全トークンを選択肢としてマッチします。 選択肢を書くのにこれは非常に面倒くさいと思うかも知れませんが、これには'$'|'@'|'%'と書くのに比べてとても大きな利点があります: 多重正規表現は容易に拡張可能です。

grammar AddASigil is Perl {
    token sigil:sym<!> { <sym> }
}
# わあ、新しいシジルを持ったPerl6グラマーができたぞ!

さらに、既存の選択肢を上書きすることもできます:

grammar WeirdSigil is Perl {
    token sigil:sym<$> { '°' }
}

このグラマーではスカラーのシジルは°なので、このグラマーはシジルを探すときは毎回$の代わりに°を探索しますが、コンパイラにはそれにマッチした正規表現がsigil:sym<$>であることが分かります。

次のレッスンでは実際の、Rakudoで動作するグラマーをお見せしましょう。

コメント

このブログの人気の投稿

Perl 5 to 6 - コンテキスト

2011-02-27: コメント欄で既に改訂された仕様の指摘がありました ので一部補足しました。 id:uasi に感謝します。 これはMoritz Lenz氏のWebサイト Perlgeek.de で公開されているブログ記事 "Perl 5 to 6" Lesson 06 - Contexts の日本語訳です。 原文は Creative Commons Attribution 3.0 Germany に基づいて公開されています。 本エントリには Creative Commons Attribution 3.0 Unported を適用します。 Original text: Copyright© 2008-2010 Moritz Lenz Japanese translation: Copyright© 2011 SATOH Koichi NAME "Perl 5 to 6" Lesson 06 - コンテキスト SYNOPSIS my @a = <a b c> my $x = @a; say $x[2]; # c say (~2).WHAT # Str() say +@a; # 3 if @a < 10 { say "short array"; } DESCRIPTION 次のように書いたとき、 $x = @a Perl5では $x は @a より少ない情報—— @a の要素数だけ——しか持ちません。 すべての情報を保存しておくためには明示的にリファレンスを取る必要があります: $x = \@a Perl6ではこれらは反対になります: デフォルトでは何も失うことなく、スカラ変数は配列を単に格納します。 これは一般要素コンテキスト(Perl5で scalar と呼ばれていたもの)及びより特化された数値、整数、文字列コンテキストの導入によって可能となりました。無効コンテキストとリストコンテキストは変更されていません。 特別な構文でコンテキストを強制できます。 構文 コンテキスト ~stuff 文字列 ?stuff 真理値 +stuff ...

LIBLINEAR 2.41 で One-class SVM が使えるようになったので Perl から触ってみよう

改訂 (Sep 15, 2020): 必要のない手順を含んでいたのでサンプルコードと記述を修正しました。 CPAN に Algorithm::LibLinear 0.22 がリリースされました (しました。) 高速な線形 SVM およびロジスティック回帰による複数の機械学習アルゴリズムを実装したライブラリである LIBLINEAR への Perl バインディングです。 利用している LIBLINEAR のバージョンが LIBLINEAR 2.30 から LIBLINEAR 2.41 に上がったことで新しいソルバが追加され、One-class SVM (OC-SVM) による一値分類が利用可能になっています (しました。) OC-SVM って何 一値分類を SVM でやること。 一値分類って何 ある値が学習したクラスに含まれるか否かを決定する問題。 HBO の「シリコンバレー」に出てきた「ホットドッグ」と「ホットドッグ以外」を識別するアプリが典型。「ホットドッグ以外」の方は犬でも神でも一つの指輪でも何でも含まれるのがミソ。 二値分類の場合正反両者のデータを集める必要があるのに対して、一値分類の学習器は正例データのみしか要求しない (ものが多い。) 主な用途は外れ値検出で、もちろんホットドッグやホットドッグ様のものを検出したりもできる。 使い方 手順自体は他の二値ないし多値分類問題と同じです。つまり、 訓練パラメータを決めて 訓練データセットで訓練して テストデータセットで確度を検証して 十分良くなったらモデルを保存する といういつもの流れ。 訓練パラメータ use 5.032 ; use Algorithm::LibLinear ; my $learner = Algorithm::LibLinear ->new( epsilon => 0.01 , nu => 0.75 , solver => ' ONECLASS_SVM ' , ); solver => 'ONECLASS_SVM' が一値分類用のソルバです。LIBLINEAR の train コマンドで言うところの -s 21 。 OC-SVM の良いところは (ハイパー)...

Perl 5 to 6 - ツイジル

これはMoritz Lenz氏のWebサイト Perlgeek.de で公開されているブログ記事 "Perl 5 to 6" Lesson 15 - Twigils の日本語訳です。 原文は Creative Commons Attribution 3.0 Germany に基づいて公開されています。 本エントリには Creative Commons Attribution 3.0 Unported を適用します。 Original text: Copyright© 2008-2010 Moritz Lenz Japanese translation: Copyright© 2011 SATOH Koichi NAME "Perl 5 to 6" Lesson 15 - ツイジル SYNOPSIS class Foo { has $.bar; has $!baz; } my @stuff = sort { $^b[1] <=> $^a[1]}, [1, 2], [0, 3], [4, 8]; my $block = { say "This is the named 'foo' parameter: $:foo" }; $block(:foo<bar>); say "This is file $?FILE on line $?LINE" say "A CGI script" if %*ENV.exists('DOCUMENT_ROOT'); DESCRIPTION いくつかの変数にはツイジルという第2のシジルがあります。これは基本的にはその変数が「普通」ではないということです。違いはいくつかあり、例えばスコープの違いなどです。 オブジェクトのパブリックな属性とプライベートな属性がそれぞれ . と ! というツイジルを持つことは既に紹介しました; それらは通常の変数ではなく self に結びつけられています。 ツイジル ^ はPerl5で例外的に扱われていたケースを一般化します。次のように書けます # 注意: Perl5のコードです sort ...

多分週刊チラシの裏 (Sep 28 - Oct 04, 2020)

Chrome Web Store が有料 Chrome 拡張の取扱を終了 Chrome Web Store で提供されている有料 Chrome 拡張及びアプリ内課金 API の両方が 2021 年 1 月いっぱいで廃止される。 開発者はそれまでに代替となるサードパーティの課金 API に移行し、購入済ライセンスの移行手段も用意する必要がある。 この決定の発表時点で新規の有料ないしアプリ内課金のある Chrome 拡張の新規登録は終了している。実際のところ 2020 年 3 月時点で既に「一時的に」停止されており、その措置が恒久化されただけとの由。 シェルスクリプティングには長いオプションを使え 「短いオプション (e.g., -x ) はコマンドライン上での略記である。スクリプトにおいては自分や将来の同僚のためにも長いオプション (e.g., ---do-something ) を与える方が理解が容易だろう」という主張。 異論の余地なく正論である。 CobWeb - COBOL to WebAssembly Compiler COBOL から WebAssembly へのコンパイラ。いやマジで。 Cloudflare が何を思ったか同社のサーバレス環境である Workers に COBOL 対応を追加した際 の成果物である。 COBOL から C へのトランスレータである GNU COBOL と C コードをコンパイルして WebAssembly を出力する Emscripten から成っており、他の言語に比べて軽量なバイナリを生成するとのこと。 「ウチではそんな風にはやらないんだ (“We don’t do that here”)」 昨今ソフトウェア開発のコミュニティでも Code of Conduct を用意するところが増えてきたが、コミュニティの文化を明文化するのは難しい。 長大な「べからず集」は息苦しいし、肯定的なガイドラインは時に抽象的で実効的に使えない。問題となるようなふるまいの動機が善意であった場合は特にそうだ。 仮に優れたガイドラインがあっても、それに基いて人を実際に咎めるのは骨が折れることである。初中やればコミュニティ内でも疎まれる。 話の分かる相手ならそれでもまだ説得する意義もあるが、Web 上の対話で当事者双方が納得し合っ...

Perl 5 to 6 - Perl5の演算子に対する変更

これはMoritz Lenz氏のWebサイト Perlgeek.de で公開されているブログ記事 "Perl 5 to 6" Lesson 11 - Changes to Perl 5 Operators の日本語訳です。 原文は Creative Commons Attribution 3.0 Germany に基づいて公開されています。 本エントリには Creative Commons Attribution 3.0 Unported を適用します。 Original text: Copyright© 2008-2010 Moritz Lenz Japanese translation: Copyright© 2011 SATOH Koichi NAME "Perl 5 to 6" Lesson 11 - Perl5の演算子に対する変更 SYNOPSIS # ビット演算子 5 +| 3; # 7 6 +^ 3 # 6 5 +& 3; # 1 "b" ~| "d" # 'f' # 文字列連結 'a' ~ 'b' # 'ab' # ファイルテスト if '/etc/passwd' ~~ :e { say "exists" } # 繰り返し 'a' x 3 # 'aaa' 'a' xx 3 # 'a', 'a', 'a' # 3項演算子 $a == $b ?? 2 * $a !! $b - $a # 連結比較 if 0 <= $angle < 2 * pi { ... } DESCRIPTION 数値演算子( + , - , / , * , ** , % )はすべて元のままです。 | 、 ^ 、 & はジャンクションの生成に使われるので、ビット演算子は構文が変更されました。 それらはデータプレフィクスを伴い、例えば ...