sironekotoroの日記

Perl で楽をしたい

かんたんPerl 第2章〜第3章

さくさく進める

  • まぁ、まだ序の口なので
    • 何冊目のPerl初心者本だよというのもある
  • とはいえ、substr や index とか普段自分が使わない関数の練習ができたのは良かった

練習問題

  • 自分の回答がいまいちスマートではなかったので、本に掲載されている答えでやってみたのだけどうまく動かない
  • かんたんPerl 初版 94p Q2 (回答550p)
    • オフセットってのは文字列の先頭位置
my $year = "January 1 February 2 March 3 April 4 May 5 June 6 July 7 Augast 8 September 9 October 10 November 11 December 12";

my $month = "Mar";  # 他の月を調べたいときはここを変更する

my $name = index($year , $month);
    # これで$monthのオフセットが得られる

my $num_s = index($year , " " , $name) + 1;
    # $monthの次に出てくる空白のオフセットを探す。
    # その次($num_s)から月の順番が始まる。

my $num_e = index($year , " " , $num_s) -1;
    # さらに次に出てくる空白のオフセットを探す
    # その前($num_e)までが月の順番である

my $len = $num_e - $num_s +1;
    # 月の順番の長さ(9月までは1,10月以降は2)を得る

my $num = substr($year , $num_s , $len);
    # 月の順番を得る

say "英語で$month$num月の事です";
  • これで1〜11月までは想定した通りに動くんだけど、12月だけ $num の取得に失敗する
  • 文字列 $year の最後が、Decmber 12"; で終わっていて、最後の空白である $num_e が取得できないのが原因
    • December 12 "; のように 12 の後に1つスペースを入れるとちゃんと動く
  • で自分だったらどうするだろう、と考える。

    • この本のこの時点までで出てきた関数 print , sort , say , undef ,length , substr , index , 四則演算に文字列連結子
    • if文使えば余裕!正規表現でも行ける!のは分かるんだけど、この縛りなかなかきつい
  • とりあえず作った。我ながら雑だと思う。

use strict;
use warnings;
use 5.010;

my $year = "January 1 February 2 March 3 April 4 May 5 June 6 July 7 Augast 8 September 9 October 10 November 11 December 12";

my $month = "Dec";

my $name = index ($year , $month);
    # 月名の開始インデックスをみつける

my $num_s = index($year , " " , $name);
    # 雑に考えて、月名の後のスペース含む3文字の中には必ず月の数字が入ることを
    # 利用
    # ex) January 1 Febrary 2
    #             ___       ___
    #         空白.数字.空白
    #
    #      October 10 November 11
    #             ___         ___
    #          空白.数字.数字

my $getMonthNum = substr($year , $num_s , 3);
    #  月名スペース後の3文字を取得

my $num = $getMonthNum + 0;
    # スペースを含む文字リテラルを、数字リテラルに変換してスペースを除去する

say "英語で$month$num月の事です";
  • これで $month にDecember を入れてもちゃんと 12と返してくれる。
  • 縛り無しで書いてみた。
    • 可読性落ちてる!
use strict;
use warnings;
use 5.010;

my $year
    = "January 1 February 2 March 3 April 4 May 5 June 6 July 7 Augast 8 September 9 October 10 November 11 December 12";

my $month = "January";

my @monthName_num = split( /(\w+\s\d+)/, $year);
    # 月名 (スペース) 月の数字
    # の文字列要素に分割して、配列に格納する

my $hash_ref;
    # 格納用ハッシュリファレンス

foreach (@monthName_num) {
    if ( $_ =~ /(\w+)\s(\d+)/ ) {
        $hash_ref->{$1} = $2;
    }
    # 正規表現で月名と数字を分けてハッシュリファレンスに格納する
}

say "英語で $month$hash_ref->{$month} 月の事です";