masatoの日記

やっていきます

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をやると、たぶんすごく遅い。全部配列に読み込んでからループすればかなり速くなる。

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

VBAでExcelワークシートの間違い探しをする(差分ハイライト)

事務仕事でよくなんかのチェックリストをエクセルで作りますよね。
で、チェック項目が完了したり、内容の変更があったりして、どんどん更新されていくわけです。
更新箇所を人力で探すのは大変なので、VBAでやってみます。


手順:
1.ワークシートA、A´を比較
2.ワークシートA、A´でセルを一つずつ比較する
3.二つのセルの中身が異なれば、新しい方のセルを好きな色で塗りつぶす(今回は黄色)

Sub 変更箇所チェック()

'   作業ワークシート(シートはお好みで選択する)
    Dim wksOld As Worksheet
    Dim wksNew As Worksheet

'   古いシートが左端(インデックス=1)、新しいシートが右(インデックス=2)にあるとする。
    Set wksOld = ActiveWorkbook.Sheets(1)
    Set wksNew = ActiveWorkbook.Sheets(2)

'   セル参照用のレンジ変数
    Dim r As Range
    Dim rngOld As Range
    Set rngOld = wksOld.UsedRange

'   古いワークシートのセルを一個ずつループ
    For Each r In rngOld
        DoEvents
        
        Dim OldStr As String
        OldStr = r.Value' 古いシートの比較対象セルの中身
        If Len(OldStr) > 0 Then

            'Newシートで比較するセルの行列番号を取得し、
            'Oldシートにある同じ位置のセルを参照する
            Dim row As Long, col As Long
            row = r.row
            col = r.column
           
            Dim rngNew As Range
            Set rngNew = wksNew.Cells(row, col)
            Dim NewStr As String
            NewStr = rngNew.Value'新しいワークシートの比較対象セルの中身

            'StrComp関数で2つのセルの内容が等しいかをチェック
            '等しいときは返値が0になる
            '参考サイト:http://www.239-programing.com/excel-vba/func/func02E.html
            If strcomp(OldStr, NewStr, vbTextCompare) <> 0 Then
                rngNew.Interior.Color = 65535'黄色の定数
            End If
        End If
    Next r

'   後片付け
    Set wksNew = Nothing
    Set wksOld = Nothing
    Set rngOld = Nothing
    Set rngNew = Nothing

End Sub

中身

まず、準備から。ふたつのワークシートへの参照を簡単にするために、それぞれを変数にします。

    Dim wksOld As Worksheet
    Dim wksNew As Worksheet
    Set wksOld = ActiveWorkbook.Sheets(1)
    Set wksNew = ActiveWorkbook.Sheets(2)

wksOld,wksNewにしてみました。wks=Worksheetです。
ワークシートのインデックス(並び順)で新旧を指定してしまいましたが、順番が変わったら中身がずれてしまいますね。ベストプラクティスとしては、ワークシートオブジェクトの名前で指定する方法が推奨されています。この方法なら、並び順に影響されませんし、シート名を変えたって大丈夫です。
デフォルトでは、左のシートから`Sheet1, Sheet2`というオブジェクト名になっています。オブジェクト名(ワークシートオブジェクト)で変数を作る場合は以下のようにすればOKです。

    Dim wksOld As Worksheet
    Dim wksNew As Worksheet
    Set wksOld = Sheet1
    Set wksNew = Sheet2


次に、比較処理をやってきます。

まずデータが入っている範囲をRange型の変数にします。
ワークシート全体のうちみるべきデータがある場所を絞り込むわけです。

'   セル参照用のレンジ変数
    Dim r As Range
    Dim rngOld As Range
    Set rngOld = wksOld.UsedRange

`Set rngOld = wksOld.UsedRange`で古い方のシートのデータ範囲を変数に入れています。`UsedRange`プロパティは、シートのなかで使用済みの範囲をRange型で取得できます。列や行数を気にせずかんたんに範囲を取得できるので便利です。これで古い方のシートのデータ入力範囲が指定できました。

そうしたら次は、いよいよセルに入った値を比較していきます。
順番にセルを見ていく必要があるため、先ほどの`rngOld`を`for each`ループで回して個々のセルを参照します。`for each`ループの順番は、左上のセルから列方向に右へ進み、右端まで行ったら1つ下の行に移動します。つまりZ型です。

'   古いワークシートのセルを一個ずつループ
    For Each r In rngOld
        DoEvents
        
        Dim OldStr As String
        OldStr = r.Value' 古いシートの比較対象セルの中身
        If Len(OldStr) > 0 Then

            'Newシートで比較するセルの行列番号を取得し、
            'Oldシートにある同じ位置のセルを参照する
            Dim row As Long, col As Long
            row = r.row
            col = r.column
           
            Dim rngNew As Range
            Set rngNew = wksNew.Cells(row, col)
            Dim NewStr As String
            NewStr = rngNew.Value

            'StrComp関数で2つのセルの内容が等しいかをチェック
            '等しいときは返値が0になる
            '参考サイト:http://www.239-programing.com/excel-vba/func/func02E.html
            If strcomp(OldStr, NewStr, vbTextCompare) <> 0 Then
                rngNew.Interior.Color = 65535'黄色の定数
            End If
        End If
    Next r

空のセルは見なくてよいので、 `If Len(OldStr) > 0 Then...` という条件分岐でスキップさせます。参照範囲が増えると、それだけセルの数が増すので、そもそも比較しなくてよいセルをスキップしよう、ということです。これでちょっと速くなります。

で、次にセルの行と列の番号を取得します。新しい方のシートで、その位置のセルを参照するためです。それがこの部分。

Dim rngNew As Range
Set rngNew = wksNew.Cells(row, col)
Dim NewStr As String
NewStr = rngNew.Value'新しいワークシートの比較対象セルの中身

rngNewにさっき見た古いワークシートのセル位置にある新しい方のワークシートのセルを入れます。

最後に、古いシートと新しいシートで値が入っているセルの位置がずれていると、ちゃんと比較できません。

好きな音楽について語ろう ~弱いうた編~

つかれたときによく聴く歌がある。

最近よいと思ったのはcoccoだ。数年前はcoccoの良さがわからなかった。鬼束ちひろの方が絶対いいと思っていた。だが、いまになってわかる。とてもいい。coccoは真実だ。

松崎ナオも好きだ。とくに「光が生まれる日まで」(「虹盤」収録)、「空の部屋」(「気持ちバタフライ」)、「川べりの家」(「Flower Source 」)が刺さる。「あなたに向かって」もおすすめだ。幻想的な曲で、これを聴くとこころの深いところが疼いて、ひりひりして泣きそうになる。厨二的感性の持ち主に響くはずだ。Amazonで中古盤が300円くらいで売っていた。ほしい。

これらの歌にカテゴリ付けするとすれば、「弱さをさらけ出す歌」という感じだろうか。自分の場合、このポジションはみんな女性アーティストだ。そして、そうじて艶っぽいところがある。そこがまたいい。

男性の弱々系も、ある。しかし彼らの曲は破滅的すぎて、平穏な日常にはそぐわない。カートコバーンはかっこよかった。自己嫌悪が強すぎるが。エリオット・スミスはどうか。見た目はなんともいえないけど、アコースティックギターと悲しげで線の細い声が、鬱々とした気持ちを盛り上げてくれた。一人で絶望するときのお供に割と聴いた。曲の雰囲気はかなり末期的で心底絶望しているときにはぴったりだった。イメージは、色で言うと真っ青、季節では冬。まさに絶望。エリオット・スミス的絶望に近い波長は、森田童子が思い出される。あれは、確かな鬱だった。

この曲たち、いまは全然聴いていない。聴かなくても生活できるようになったのは、成長したということだろうか。


あなたに向かって - 松崎ナオ