masatoの日記

やっていきます

夕食の量をへらしてみる

最近、春が来たということもあって、暖かいので、つられて延々と眠ってしまいがち。

週末なんて10時間以上も寝ている。二度寝、三度寝しているからなんですけどね。

春というのを別にしても、7時間は寝ないと調子が出ない。

もっと短い睡眠時間で元気に生きられるとうれしいという思いがあって、食事の量を減らしてみようと思っています。

ただ、減らしすぎると体重が減るので、一日のカロリー量を保ったまま3食に分配できればよい。

Text::XslateでTMを作ってみた

TMつくりが地味に大変

ある程度成果物がたまったら、訳文を翻訳メモリにして、再利用できるようにまとめておきたい。

CATツールにはOmegaTを使っていて、翻訳メモリはTMX形式だ。中身には原文、訳文、原文言語、訳文言語などが含まれていて、これらはXMLで構造化されている。

翻訳メモリをつくるためのツールはいろいろあって、いくつか試してはみた。

しかしうまくいくときもあるけど、訳文と原文のペアがズレることが多くて悩ましい。

普段はOmegaTのAlignerというテキスト整合用プラグインを使ってるのだけれど、これだと分節化する箇所をうまく設定できない(とういか、やり方がわからない)。

たとえば、「Mr.」とか「etc.」の後のピリオドで分節化するのはよしてほしいのだけど、OmegaTはそこで区切ってしまうのだ。

分節化規則で区切らないように正規表現を入れてはいる。それで正しいはず。はずだが、うまくいかない。

同数の分節からなる原文と訳文ファイルを合体させたい、だけなのに。

前置きが長くなりましたが、余計な分節化が入らないように自作ツールを作ってみました。備忘録的にまとめます。

テンプレートエンジン

TMXファイルの中身はXML。テンプレートを使って自由にテキストファイルを生成できるText::Xslateを使いました。 まず、ひな形を用意します。

材料1:TMXファイルひな形(XML

OmegaTが自動生成するTMXファイルはこんな構造。

<tu>
  <tuv lang="<: $source_lang :>">
    <seg><: $source_body :></seg>
  </tuv>
  <tuv lang="<: $target_lang :>" changeid="<: $translator :>" changedate="<: $change_date :>" creationid="<: $id :>" creationdate="<: $createn_date :>">
    <seg><: target_body :></seg>
  </tuv>
</tu>
<tu>

<: $hoge :>の部分は、Text::XslateのKolonシンタックスで書いた変数展開パターンです。 TMXの要素である言語指定、原文、訳文などをこれらの箇所に挿入していきます。

材料2:スクリプト本体

ファイル名指定

このコードではシェルから実行して、訳文ファイル、原文ファイルをタイプする形にしています。 ファイルは半角スペース区切りでsource.txt target.txtのように入力すると、それぞれ$src$target変数に入ってくれます。 $targetの方はchompしないと改行コードが入るので注意。

#!/usr/bin/perl
use strict;
use warnings;
use utf8;
use Text::Xslate;
use Time::Piece;

# ソース、ターゲットファイルを読み込む
print "Type file name (source, target):\n";
my ($src, $target ) = split(/ /, <STDIN>);
chomp($target);

言語指定

#言語設定
print "Type languages (source, target. e.g. JA EN):\n";
my ( $srclang, $targetlang ) = split(/ /, <STDIN>);
chomp($targetlang);

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

シェルでタイプしたテキストファイルを読み込むサブルーチン。 原文と訳文テキストをこれで読み取ります。

sub get_body {
    my $file = shift;
    my @body = ();

    open (my $fh, '<', $file) or die qq/ Can't open "$file": $!/;
    while (<$fh>) {
        chomp;
        push (@body, $_);
    }
    close ($fh);

    return @body;
}

次、読んだテキストをText::Xslateに渡せる形にします。 引数は配列レファレンスにする必要があるようでした。 なので、配列レファレンスにハッシュレファレンスを入れてやります。

こんな感じ。

my $segments = [
    {
      srcbody    => 'Apple',
      targetbody => 'りんご',
      srclang    => 'EN',
      targetlang => 'JA',
    },
    .......
];

ハッシュレフ一つが1文節のペアに対応します。 なので、たとえば100文節のTMを作る場合はこの配列レファレンスに100個のハッシュレフを入れればいいですね!

sub generate_template_arg {
    my ( $src, $target ) = @_;

    # 配列レファレンスにハッシュレフを入れる
    my $segments;
    for my $segment (@$src) {
        my $hash_ref = {
            srcbody  => $segment,
            targetbody => shift @$target,
        };
        push (@$segments, $hash_ref);
    }

    p $segments;
    return $segments;
}

ここまででテキストファイルの中身をText::Xslateに渡せる形にできました。 以下でテンプレートをもとにTMXファイルを作ります。

sub generate_tmx {
    my ( $segments, $srclang, $targetlang ) = @_;

  # イニシャライズ
    my $tx = Text::Xslate->new();

    # 生成するTMXのファイル名を指定
    my $tmx = 'translation_memory.tmx';

    open (my $out, '>', $tmx) or die $!;
    print $out $tx->render('test_template.tx', {
                            segments   => $segments,
                            srclang    => $srclang,
                            targetlang => $targetlang,
                         });
    close ($out);
}

この例では、$segmentsの中にすべての分節が収まっています。 TMXのファイル名はハードコードじゃなくて、引数で指定できるようにしたいところです。

順番が前後しましたが、上記のサブルーチン呼び出し部です。

# ハッシュの配列をもらう(Xslateで展開するため)
my @srcbody = get_body($src);
my @targetbody = get_body($target);

# 原文、訳文をXslateに渡す形にまとめる
my $segments = generate_template_arg( \@srcbody, \@targetbody );

# テンプレートエンジン起動
&generate_tmx( $segments, $srclang, $targetlang );

補足

Excelからソースを取ってくる場合、セル内の改行を適当な符号に置き換えること。

でないと、分節の対応がズレます。

Office TanakaのサイトExcelのセル内改行を置換する方法が詳しく説明されています。

ざっくりいうと、置換窓の検索欄でCtrl+Jを押すと、改行コードが入力できます。(見た目は変化ないです。透明。)訂正:Ctrl+Jするとドットが点滅する状態になりました。Office 365のExcelWindows 10で確認)

それで置換欄になんでもいいのでちょうどよい文字列を入れて置換します。正規表現のメタ文字にならって\nでいいのではないでしょうか。

で、改行コードを\nと置換したファイルを材料に上記のPerlスクリプトでTMXを生成します。

そいつをテキストエディタで開き、\nを本物の改行コードに置換してやれば完成です。

お疲れさまでした。

PerlのWAF Amon2で検索窓をつくってみる

Perlを勉強するかたわらAmon2でチュートリアル的なブログサイトを作っております。 さくらのVPSで。

さて、ブログを含めインターネットでよく見かける検索窓を自分のブログサイトにもほしくなりました。 そのあれをつくってみます。

HTML(index.tx)

<form action="/search">
  <input type="text" name="search_word">
  <button type="submit" id="search">Search</button>
</form>

こんなの。 f:id:masatoz:20170416230651p:plain

サーバー側(コントローラー)

package MyApp::Web::C::Root;

sub search {
    my ( $class, $c) = @_;

    # 検索語を取得・・・①
    my $search_word = $c->req->parameters->{search_word};
    
    # LIKE 検索・・・②
    my @matches = $c->db->search('schedules', [ 'body', {'like' => "%$search_word%"} ]);
    return $c->render('index.tx', { schedules => \@matches });
}

コメント

Plack::RequestのparametersメソッドがAmon2の$cオブジェクトから使える。 HTMLに記述した<input name="search_word"></input>フィールドの入力を取得するためには、$c->req->parameters->{search_word}とすればいいです。

参考リンク(CPANPlack::Request - search.cpan.org

② Amon2の標準で使えるO/RマッパーTengを使ってLIKE検索する。 こちらのサイトを参考にさせていただきました。 とてもわかりやすいリファレンスです。

PerlのO/RマッパーTengの簡単なリファレンス | UCWD-Studio - @matsuoka_UCWDjp 's Private Projects.

DEMO

実際のデモサイトです。 つくりかけのあれこれが散らかっていますが気にしないでください。 Scheduler

初めてのPerl 6章ハッシュ 練習問題1

プログラミングの参考書をなるほどなるほど、と読みすすめてみても、本を置き、書こうとすると出てこない。 本当に。

なので、まず書いてみようということで、どんどん手を動かしていこう。打ちながら、わからなくなったら本を開けばいい。

ということで、「初めてのPerl」第6章ハッシュからの問1。自分用のメモを残しておく。

use strict;
use warnings;

## 姓名を標準入力で入力してもらって、その人の姓を表示するプログラム
## あいだを半角スペースで区切ってね
print "Input your name:(Finish with type 'q')";

my %fullnames;

while (my $fullname = <STDIN>) {
    chomp($fullname);
    if ($fullname eq 'q') { last; }
    
    my ( $first_name, $last_name ) = split(/ /, $fullname);
    print "$first_name $last_name";

    # 名をハッシュのキー、姓を値とする
    $fullnames{$first_name} = $last_name;

    print "Input next name:";
}

for my $last_name (keys %fullnames) {
    print $fullnames{$last_name},"\n";
}

やりたいこと

標準入力から姓名をスペース区切りで入力すると、名字だけを表示する。

入力と結果

Input your name:(Finish with type 'q')Kondo Satoshi
Input next name:Suzuki Munenori
Input next name:q
Munenori
Satoshi

つまったところ

ハッシュに要素を追加する方法でつまづいた。 はじめにやった方法は

%fullnames = (
    first_name => $first_name,
    last_name  => $last_name,
};

これだと、ループのたびに上書きされるので、最終的に一つの要素しか作れない。 この場合、キーがfirst_namelast_nameで固定されているので、値を追加しても自動的に要素が生成されないのだった。

上記は普通のハッシュだった。

これをハッシュレフでやったのが以下だ。

my $fullnames_ref;

while (my $fullname = <STDIN>) {
    chomp($fullname);
    if ($fullname eq 'q') { last; }
    
    my ( $first_name, $last_name ) = split(/ /, $fullname);

    # 名をハッシュのキー、姓を値とする
    $fullnames_ref->{$first_name} = $last_name;

    print "Input next name:";
}

for my $last_name (keys %$fullnames_ref) {
    print $fullnames_ref->{$last_name},"\n";
}

ハッシュのシジル(%→$)を変更したのと、参照方法を変えただけでOK。

ハッシュの値参照: $fullnames{$first_name} #$first_nameに対応する$last_nameが取り出せる

ハッシュレフの値参照: $fullnames_ref->{$first_name} #上に同じ

初めてのPerl 練習メモ 第5章 入出力

なんでもブログに書くといいことがあると聞いて、雑でもいいから勉強の記録をUPしてみることにします。 今日は「初めてのPerl」の練習問題をやりました。5章 入出力です。

問1.

やりたいこと

標準入力で入力した文字列をおしりから頭に向かって逆順にプリント。 複数行入力した場合は、一番最後の行から最初の行に向かってプリントする。

use strict;
use warnings;

# tacプログラム:入力した文字列を逆にプリントする
# Satoshi Takashi Hisanori みたいに半角スペースで区切ってタイプする
chomp(my $in = <STDIN>);
if (length($in) == 0) {
    die $!;
}

my @names = split(/ /, $in);
for my $name (reverse @names) {
    my $rev = reverse($name);
    print $rev,"\n";
}

結果

入力

Satoshi Hisashi Takatoshi

結果

ihsotakaT
ihsasiH
ihsotaS

問2.

やりたいこと

10文字で右揃えにしてプリントする。 たとえば、'hoge'4文字ならスペースを6文字追加してからプリントする。

use strict;
use warnings;

print "Input strigs. If you want to finish, type 'q'.";

my @str = ();
while (my $input = <STDIN>) {
    print "next:\n";
    if (chomp($input) ne 'q') {
        push (@str, $input);
    }

    if ($input eq 'q') { last; } 
}

my $scale = '123457890';
print $scale x 5,"\n";

for my $str (@str) {
    my $len = length($str);
    my $space = ' ' x (9 - $len);
    print "$space$str\n";
}

問3.

やりたいこと

問2の拡張版。右揃えにする文字数の幅を標準入力から指定できるようにする。 たとえば、30字でそろえたい場合、はじめに30と入力してから、それ以降に文字列をタイプする。

use strict;
use warnings;

my @str = ();
my $c = 0;

print "Input strigs. If you want to finish, type 'q'.";
print "Hon many columns you want?\n";
my $column_number = 0;

while (chomp(my $input = <STDIN>)) {
    if ($c == 0) { 
        $column_number = $input;
        print "Input next:\n";
        $c++;
    } else {
        print "Input next:\n";
    }
    
    if ($input ne 'q') {
        push (@str, $input);
    } elsif ($input eq 'q') {
        last;
    }
}

my $scale = '123457890';
print $scale x ( $column_number),"\n";

shift(@str);
for my $str (@str) {
    my $len = length($str);
    my $space = ' ' x ($column_number -1 - $len);
    print "$space$str\n";
}

ところどころ結構ヘンなところがあるけど、練習ということでそのままにしておく。

食物不耐症の話

ジョコビッチ本」との出会い

たまたまジュンク堂名古屋栄店のB1でぶらぶらしてたとき、ジョコビッチ本を手に取りました。 ジョコビッチは、あの世界的テニスプレーヤーのことです。 ジョコビッチが実は小麦を食べると体調が悪くなる体質だったらしいです。 ジョコビッチはそのことをある有名な医師に診てもらうことで、知ることができたのでした。 ざっくりいうと、食生活を変えたら絶好調だ、おれはこういうモノを食べるようにしている、という内容が続いていて、自分もやってみたくなりました。

去年11月のことです。

食生活を変える動機

そもそも、その本を手に取ったのは、自分のカラダはなんかよくないという感覚があったからでした。 その頃は、普段から午後2,3時になると疲れてしまい、すぐにだるくなってました。 平日は仕事なのでアレですが、休日は実際そんな感じで横になって小休憩することで一日をしのいでいるという状態だったのです。

そんな疲れやすい体質を改善したいという思いはずっともっていて、体質が改善するなら食生活を変えることはたやすいことに思えました。

人によって身体に合わないたべものは違う

ジョコビッチがダメだったのは主に小麦でした。 「小麦 食物不耐症」みたいなキーワードでGoogleとかAmazonとかで探すと、わんさと関連情報が出てきました。 それで、どうやら小麦が合わない人は多いらしいということがわかったのです。 実際自分もそうなのかどうかは、やってみないとわからないワケで、やってみました。 結論としては、OKだったと思います。ただ、その他にも色々実践していたので、小麦だけ、とは限定できないことは断っておきたいです。

 「最強の食事」を読んだ

その2か月くらい後には「最強の食事」という、知る人は知ってるだろうかなりストイックな本を読みました。 で、長くなるのではしょりますが、そこに書いてあることも色々やってみました。

ひとつに絞るなら「ケトン体質」になるべく食生活を変えました。 それで絶好調になったかというとそうでもなく、とくに筋肉が落ちたのはダメでした。

その時の私は、炭水化物を極力摂らないようにし、良質な野菜と良質な脂質、そして良質なたんぱく質を極力摂取するようにしていました。 思ってもみなかったのですが、筋肉を維持・成長させるには、たんぱく質ばかりどかどか取り込んでもダメで、炭水化物が必須であるようなのでした。 筋トレしつつ、たんぱく質と野菜を摂って、カラダをたくましくしようという気持ちもあったのですが、炭水化物をほとんど摂らなかったので、カラダが回復せずにかなりしんどい思いをしました。 一例をあげると、ベンチプレスで上がるウエイトがケトン食前後で10kg落ちました。

こう判断するのは、あとで炭水化物をまた摂るようになってから力が戻り、ネットでそのあたりを調べたらどうも炭水化物は筋肉に必須らしいとわかったのでした。 個人の経験+ネット情報、とういことです。

ただし、うまいこと炭水化物を補給するなどすれば、筋力を損なわずにケトン体質になれるのかもしれないので、いつかその気になったらやってみるとおもしろいかもです。

でも、個人差がある

僕の場合は小麦をやめるとか、果物を取り過ぎないとか、精製糖類(果糖ぶどう糖液糖など)を食べるのをやめてから体調がずっとよくなりました。 身体に悪いとされる食物を断つ一方で、積極的にカラダに良い食べ物も取ってました。サケとかサケとかブロッコリーとか。

ただ、気をつけたいのは、これがだれにでも当てはまるワケではないということです。 だから、人に自分の成功パターンを押しつけるのは危険です。 それは、そもそもその人に対して効果がないかもしれないし、第一、食生活を大きく変えるのは一般的にいってストレスが大きいのでなおさら負担をかけることになるでしょう。

なにが合うか合わないかを知るために、血液検査が役に立つかもしれません。 アンブロシア株式会社|アレルギー検査キット|食物アレルギー|遅延型フードアレルギー

科学が好きな人であれば、自分を動機付けやすいでしょうし、何十品目についての不耐症度を示してくれるので便利です。 私はこれのうちの1つ(いろんなタイプがあります)をやってみて、小麦と卵の不耐症度が高く出ていました。 卵には苦手意識がなかったので、これは意外でした。 それ以降、大量の卵を食べることはなくなりましたが、少量であれば普通に食べてます。 たとえ、この検査で合わない度合が高い食べ物であっても、重度のアレルギーといった場合を除けば、量さえ少くしておけば、不自由なく食事が楽しめます。 あまりきちきちに制限せず、適度にゆるくするのが楽でよいかと最近は思っています。

Excelで正規表現を使って置換するためのマクロについて、メモ

今日仕事でいつものようにエクセルを使っているとき、エクセルってワイルドカード使えんかったっけ、とふと思い、ググった。 で、実はエクセルはごくごく限られたワイルドカードしかサポートしていなくて、ワードみたいにあれこれできんのだった。

みんなエクセル文書はありふれているというのに、置換がまともにできないのは非常に不便ではないだろうか。

なので、VBAからRegexインスタンスを立ち上げて、セルをループしてやって置換すればいいと思った。

ざっくりした手順: 1.UsedRangeを変数に入れる 2.UsedRange変数をループして、中身と行列番号を多段配列とかその他の配列っぽいやつに収める 3.配列をループして、Whatを探し、見つかったらRegexの関数をCallして置換し、置換した文字列を返して、配列の行列番号から元のセルを参照してValueプロパティに戻してやる。

2は、高速化のためだ。1のRangeをループして3をやると、たぶんすごく遅い。全部配列に読み込んでからループすればかなり速くなる。

エクセルでこれができたらかなり便利になると思う。