masatoの日記

やっていきます

正規表現で名前付きキャプチャを使う

正規表現パターンがある程度ややこしくなると、後方参照でキャプチャの順番を書くのが大変になります。

そこで番号ではなくて名前でキャプチャを指定できるという名前付きキャプチャを試してみました。

Perlでは(?<name>)とするとキャプチャに名前が付きます。
名前付きキャプチャで補足した結果は%+というハッシュに記憶されるようです。

サンプル。

my $str = '0123 The message: "The weather today is great" is displayed.';

my $p = '\A(?<no>\d+).*?"(?<quoted>.*?)".*\Z';

$str =~ /$p/;

# 名前付きキャプチャは$+{name}で参照できる
my $index = $+{no}; # 0123
my $quoted = $+{quoted}; # The weather today is great

このときの%+をダンプしてみるとこんなふうになってました。

use Data::printer;
p %+;

普通のハッシュです。

Tie::Hash::NamedCaptureというものがあるようです。

{
    no       "0123",
    quoted   "The weather today is great"
} (tied to Tie::Hash::NamedCapture)

感想

キャプチャした箇所をハッシュにまとめられるので、管理しやすそうだと思いました。

grepを使ってリストにマッチする要素が含まれるかを判定する

ループの代わりにgrepすると簡潔に書ける。

人の名前がはいったリストがあるとして、その中にFredさんがいるかどうかを確かめたい。
forループならこう書ける。

for my $person ( @people ) {
    next unless $person =~ /Fred/;
    $flag = 1;
    last;
}

grepを使うと1行だ。

my $ret = grep { /Fred/ } @people;

結果のプリントを含めたサンプルコード。

use strict;
use warnings;
use 5.0100001;

my @people = qw/ Jeff Masato Koji /;

## forループを使った場合
my $flag;
for my $person ( @people ) {
    next unless $person =~ /Fred/;
    $flag = 1;
    last;
}

if ($flag) {
    say $flag;
} else {
    say "Fred doesn't seem to be here."
}

## grep演算子を使った場合
my $ret = grep { /Fred/ } @people;

if ($ret) {
    say "Hi, Fred.";
} else {
    say "Fred isn't here.";
}

テキストファイルを一気に読み込む

Whileループじゃなくて一気に中身を変数にいれたいときはこうする。

my $str = do {
    open my $fh, '<', $file or die $!;
    local $/ = undef;
    <$fh>;
};

local $/ = undefとやるとdoブロック内でのみ改行コードを無視できる。

 readline関数が一度に読み取るのは、$/ に設定されている文字が出現するまでです。$/は、インプットレコードセパレータといい、デフォルトでは \n 、改行文字が設定されています。

すべての行をスカラ変数に読み込む すべての行を配列に読み込む - PerlならサンプルコードPerl入門

Perlで正規表現を使って日本語の文字列にマッチさせる

やりたいこと

日本語の文字列に任意の文字列が含まれるかどうか判定したい。

二通りのやりかたを書く。

正規表現でマッチさせる

use Encode qw/encode/;

# source text
my $str = 'メッセージ”通信エラー”が表示されます。';
my $p = '通信エラー';

$p = encode('utf8', $p);
$str = encode('utf8', $str);

if ($str =~ m/$p/) { # マッチをトライ
    print "Found it!!!";
}

index関数を使う

あるいは、index関数を使って任意の文字列が含まれるかどうかを判定できる。

## index function
if (index($str, $p) >=0) {
    print "Found it!!!\n";
}

メタ文字にマッチさせたいときは、\エスケープしてもよいが、quotemetaすれば自動でエスケープされて便利。

## quotemeta
my $qp = quotemeta $p;
if ($str =~ s/$qp/Communication fault/) {
    print "Replaced: $str\n";
}

名前付きキャプチャを使って複雑なマッチに対処する

正規表現でキャプチャしたグループは、$1, $2...という変数で参照できる。 だけどごちゃごちゃした文字列をキャプチャして参照したいときは、名前で参照できたほうが簡単だ。

キャプチャしたグループに名前をつけるには、(?<tag>)というふうに書く(tagは任意の名前)。 名前付きキャプチャの結果は%+というハッシュに入る。個別の要素を、指定した名前をキーとして参照できる。つまり、$+{tag}という具合。

my $line = 'no:1234 item_name:banana price:160 qty:8';
$line =~ /\Ano:(?<no>\d+)\s*
              item_name:(?<item_name>.*)\s*
              price:(?<price>\d+)\s*
              qty:(?<qty>\d+)\s?*
              \z/x;

print "番号:$+{no}\n";
print "品名:$+{item_name}\n";
print "価格:$+{price}\n";
print "数量:$+{qty}\n";

# 番号:1234
# 品名:banana
# 価格:160
# 数量:8

AjaxをやるときのHTMLとサーバー側コードの書き方を整理する

Ajaxをやろうとして沼だったので、書いて整理したい。

jQuery$.ajaxを使う一方で画面遷移が起こらないようにpreventDefaultでブラウザのリクエストを止めるか、そもそもHTMLでSubmitしないようにする必要がある。

NGパターン

Ajaxなのに画面遷移してしまう

Ajaxなのに画面遷移してしまう残念パターン。

HTMLでSubmitする+jsでpreventDefaultしていない

OKパターン

ちゃんと非同期通信できるのは

HTMLでSubmitしない or HTMLでSubmitする+jsでpreventDefaultする

とても参考になるリンクがあったので貼る。

ふじこのプログラミング奮闘記 - jQueryのバブリングと、「return false;」「e.stopPropagation();」「e.preventDefault();」について

ナビなしで高速道路を走れない

きのう名古屋市内の住まいから豊田市の実家に用事があり、急いでいたので高速道路でいった。

ナビに目的地をセットして車を出した。

しかしナビが示したのは一般道だった。走行中にルート変更できないヤツなので、ナビはあきらめて記憶とカンに頼って走ることに決めた。

何度目かの高速分岐にて、なぜか四日市方面に向かっていた。それは間違いで、結局ものすごい大回りをしていくことになってしまった。

道オンチで迷うことはよくある。

高速の分岐では、「たぶんこっち」で選んだ先は8割くらい間違っている。

早く目的地に着きたいがためにお金を払って高速にのっているのに、時間はかかるし、ガソリンはなくなるし、せつない。

自分に対してアホなのか?という気分だ。

さて不思議なことに道がわからないのに調べることをしない。

それはたぶん、調べるのがめんどくさいからだ。

そもそも調べたことがほとんどないので、調べ方が大変そうに感じてしまう。

道順を記憶することに興味あまりないなあ。

車のドア収容に備えてあるマップルは、いまだかつて活用したことがない。

地理をパラパラ眺めてみたことはある。

いや、そういうことじゃなくて。

道順がわからないと私生活でも仕事でもかなり困るはずだし、実際けっこう困っているのだ。

そろそろ道に詳しくなるために努力したほうがいいかもしれないとぼんやりと考えた。

OmegaTの分節化規則: ピリオドの後で分節化するのを避けるには

OmegaTで英文を分節化するときにうまくいかなかったけど、今日発見があったのでメモします。

やりたいこと

英語で複数の文章を1文節とした場合にピリオドの直後に続くスペースで分節化しない。

NGケース:

f:id:masatoz:20170418155513p:plain

This. is. a. sample. sentence.という、通常ありえない文ではありますが、改行なしで一続きのテキストがあります。 改行のみで分節化してほしい場合、これでは困ります。

方法

「分節化規則」の「初期値」をいじるとピリオドの後で分節化するのを避けることができます。

f:id:masatoz:20170418155144p:plain

ここに前方の正規表現[\.\?\!]+、後方の正規表現\sという項目があります。 .(ピリオド)または?(クエスチョンマーク)、!(エクスフラメーションマーク)の直後に1文字以上のスペースが続く場合に分節化する、ということになっています。

なので、これのチェックをはずします。 設定を変更して、再読み込みします。

こうなりました。OK! f:id:masatoz:20170418155711p:plain

この設定が有効になっていると、デフォルトで用意されている「Mr.」「etc.」などを分節化しない設定が無効になります。

設定をみてみると

f:id:masatoz:20170418160131p:plain

こんな感じです。

後方の正規表現にみな\sがあります。

ということはetc.が来て、直後に一文字以上のスペースが来たら分節化する、の意になります。

しかし.(ピリオド)の直後に一字以上のスペースの方が先に適用されてしまうので、上記の表現はみんな効かなくなってしまいます。