ChaichanPapa-World !

燈明日記(2007/12

◆ インデックス

◆ 2007年12月

2007-12-31 有難嬉悲しメモ(2007/12/31)

まずは、本年最後の挨拶です。

今年は、家庭も仕事も前年に比べれば安定して、有り難かったです。

本ブログも、アクセスしていただける皆様のお陰様で、充実することができました。ありがとうございました。

来年も、ガンガン行きますので、よろしくお願いいたします。


ちなみに、『有難嬉悲しメモ』とは、その日に起こった以下の3つのことを綴っています。

  1. その日で一番有り難かったこと
  2. その日で一番嬉しかったこと
  3. その日で一番悲しかったこと

では、今年最後の有難嬉悲しメモです。


補足:

私は、『ごくせん』と『華麗なる一族』を両方とも再放送ではじめて見ました。

2007-12-30 有難嬉悲しメモ(2007/12/30)


補足:『華麗なる一族』

キムタクの役の生き様に感動でした。特に突貫工事のくだり。

2007-12-30 漢字クッキーをPerlでSetし、JavaScriptでGetする!

まずは、以下の引用(質問と回答)をご覧ください。


質問

ieのjavascriptでescapeすると

おはよう ⇒ %u304A%u306F%u3088%u3046

となりますが、これをperlなどで同じように

エンコードする方法はありませんでしょうか?

http://oshiete1.goo.ne.jp/kotaeru.php3?q=1257793

回答

使い方は

  $escaped_str = js_escape($str, $icode);

となります。

$icode には $str のエンコーディング("sjis" や "euc-jp" など)を指定して下さい。

# print js_escape("おはよう", "sjis"); など

sub js_escape {
    use Encode;
    my $str = join "", map sprintf("%%u%04X", $_), unpack "n*", encode("utf16be", decode($_[1], $_[0]));
    my ($ch, $hex);
    $str =~ s<%u00(..)>{ ($ch = pack("H2", $hex = $1)) =~ m<[^\w\@.*/+-]> ? "%$hex" : $ch }eg;
    $str;
}
http://oshiete1.goo.ne.jp/kotaeru.php3?q=1257793

js_escapeの解説
  1. join...のソースのdecode($_[1], $_[0])は、$_[0]の文字列を$_[1]で指定された漢字コードからUTF-8にデコードしています。
  2. encode("utf16be", decode($_[1], $_[0]))は、1でデコードしたものをutf16beにエンコードしています。
  3. unpack "n*", encode("utf16be", decode($_[1], $_[0]))は、2でエンコードしたものをリストにアンパックしています。
  4. map sprintf("%%u%04X", $_)は、3を%uXXXXの形式にフォーマットし、それらのリストを返します。
  5. join ""は、4のリストを連結して一つの文字列にします。
  6. s<%u00(..)>...のソースは、1バイト文字(%u00(..))を、[^\w\@.*/+-]で弾いたものは%$hexとし、それ以外は$chとして置換します。
  7. 留意点としては、置換や検索の区切り文字に<>や{}を使用しています。
  8. つまり、join...のソースは、2バイト系(漢字)をデコードし、 s<%u00(..)>...のソースは1バイト系をデコードしています。

以下にjs_escapeを使ったサンプルをアップしときます。


CGI(Perl)ソース(漢字クッキーをPerlでSetする)
#!/usr/local/bin/perl
use strict;

&set_cooKie('test_javascript_cookie1', 'ID:111,X X:あ,YY:1あ1,ZZ:あ1あ', 1,'','/');
&set_cooKie('test_javascript_cookie2', 'ID:111,XXX:い,YY:1あ1,ZZ:あ1あ', 1,'','/');

print <<"HERE1";
Content-type: text/html; charset=Shift_JIS

<html>
<body>
<p>漢字クッキーをPerlでSetし、JavaScriptでGetする!</p>
</body>
</html>
HERE1

sub set_cooKie {
    my ($CookieName, $cookie, $daycount, $domain, $path) = @_;
    my ($secg,$ming,$hourg,$mdayg,$mong,$yearg,$wdayg) = gmtime(time + $daycount*24*60*60);
    my @week = ('Sun','Mon','Tue','Wed','Thu','Fri','Sat');
    my @mons = ('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec');
    my $date_g = sprintf("%s, %02d\-%s\-%04d %02d:%02d:%02d GMT",
       $week[$wdayg],$mdayg,$mons[$mong],$yearg+1900,$hourg,$ming,$secg);
    $cookie = js_escape($cookie, "sjis");
    if ($domain eq '' && $path eq '') {
        print "Set-Cookie: $CookieName=$cookie; expires=$date_g; \n";
    }
    elsif ($domain eq '') {
        print "Set-Cookie: $CookieName=$cookie; expires=$date_g; path=$path; \n";
    }
    elsif ($path eq '') {
        print "Set-Cookie: $CookieName=$cookie; expires=$date_g; domain=$domain; \n";
    }
    else{
        print "Set-Cookie: $CookieName=$cookie; expires=$date_g; domain=$domain; path=$path \n";
    }
}

sub js_escape {
    use Encode;
    my $str = join "", map sprintf("%%u%04X", $_), unpack "n*", encode("utf16be", decode($_[1], $_[0]));
    my ($ch, $hex);
    $str =~ s<%u00(..)>{ ($ch = pack("H2", $hex = $1)) =~ m<[^\w\@.*/+-]> ? "%$hex" : $ch }eg;
    $str;
}

HTML(JavaScript)ソース(漢字クッキーをJavaScriptでGetする)
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS">
<title>漢字クッキーをPerlでSetし、JavaScriptでGetする!</title>
</head>
<body>
<script type="text/javascript">
function getCookie(){
        this.data = new Array();
        this.string = (document.cookie) ? document.cookie.split(';') : new Array();
        for (var i = 0; i != this.string.length; i++) {
             this.data[this.string[i].split('=')[0].match(/[^ ].*/)]
                                  = unescape(this.string[i].split('=')[1]);
        }
}
getCookie = new getCookie();
document.write(getCookie.data.test_javascript_cookie1, "<br>");
document.write(getCookie.data.test_javascript_cookie2, "<br>");
</script>
</body>
</html>

2007-12-29 有難嬉悲しメモ(2007/12/29)

2007-12-29 Perlでの多次元配列アクセス

Perlでは、言語仕様的には、多次元配列は、ありません。

しかし、配列のリファレンスを配列の要素にすることで、あたかも多次元配列を実現することが出来るのです。

多次元配列は結構難解で、言葉で説明すると余計に混乱するので、以下のサンプルをヒントにしてみてください。


基本的には、リファレンスはスカラー値で、変数名の前に『\』添えて表記します。

そのリファレンスから元の値にアクセスすることをデリファレンスいいます。

元がスカラーのリファレンスのデリファレンスは、変数名に『$』を添えて表記します。

また、配列の最大インデックスは、変数名に『$#』を添えて表記します。

my @aaa = ('aaa', 'bbb', 'ccc', 'ddd'); # 1次元配列変数
my @bbb = (\@aaa, 'eee', 'fff');        # 2次元配列変数(ただし、一番目の要素のみ2次元)
my @ccc = (\@bbb, 'ggg');               # 3次元配列変数(ただし、一番目の要素のみ3次元)
my $ddd = \@ccc;   # 3次元配列変数のリファレンスが入っているスカラー変数

# 1次元配列変数@aaaへのアクセス
print $#aaa; # @aaaの最大インデックス
print "\n";
for (my $i = 0; $i <= $#aaa; $i++) {
        print $aaa[$i], "\n";
}

# 2次元配列変数から@aaaへのアクセス
print $#{$bbb[0]}; # 2次元配列変数からの@aaaの最大インデックス
print "\n";
for (my $i = 0; $i <= $#{$bbb[0]}; $i++) {
     print ${$bbb[0]}[$i], "\n"; # 左は、$bbb[0]->[$i]や$bbb[0][$i]と等価
}

# 3次元配列変数から@aaaへのアクセス
print $#{${$ccc[0]}[0]}; # 3次元配列変数からの@aaaの最大インデックス
print "\n";
for (my $i = 0; $i <= $#{${$ccc[0]}[0]}; $i++) {
     print ${$ccc[0]}[0][$i], "\n"; # 左は、$ccc[0]->[0]->[$i]や$ccc[0][0][$i] と等価
}

# 3次元配列変数リファレンスから@aaaへのアクセス
print $#{$$ddd[0][0]}; # 3次元配列変数リファレンスからの@aaaの最大インデックス
print "\n";
for (my $i = 0; $i <= $#{$$ddd[0][0]}; $i++) {
     print ${$ddd}[0][0][$i], "\n"; # 左は、$ddd->[0]->[0]->[$i] や $$ddd[0][0][$i]と等価
}

結果的には、多次元配列の表記は、以下の通りです。

実に単純で、よかったよかった。


結果的には、多次元配列の最大インデックス表記は、以下の通りです。

実に難解なので、すこし解説です。

2007-12-28 有難嬉悲しメモ(2007/12/28)


しかし、昼間から納会でお酒を飲んでしまうと、家に帰ってから、Perlノートネタをまとめるのが億劫になってしまいますね。

ということで、今日はここまで、おやすみなさい。


そうそう、ラクダ本著者のLarry Wallは、『るろうに剣心』が好きな親日家ですね!

わたしも、大好きです。斎藤ーと比古清十郎。

2007-12-27 有難嬉悲しメモ(2007/12/27)


技術ネタは、ネタ帳に沢山あるのだけれど、PCでの動作確認やちゃんとした文章作成で、意外に大変です。

でも、ブログ更新が唯一の趣味なので楽しいです。では、おやすみなさい!

2007-12-26 有難嬉悲しメモ(2007/12/26)

補足:

IEのセキュリティを下げると、WebページからWSHが実行でき、レジストリを書き換えることが可能。

つまり、ダウンロード先PCのデフォルトローカルパスのレジストリを書き換えることができる。

詳細は、Perlノートにて近日公開予定です!

ちょっと、セキュリティ系に問題があるので、公開は断念します。

2007-12-26 配列変数へスカラー変数を代入すると?

配列変数へスカラー変数を代入すると、どうなるでしょうか?

答え:配列変数の一番目の要素になる。

my @aaa = 111;
print $aaa[0];

まぁ、ある意味、一つのデータのスライスです。

2007-12-26 配列リファレンスの元配列の最大インデックスを求める

普通の配列(@aaa)の最大インデックスは、変数名に$#をつけて$#aaaです。

では、配列リファレンスの場合は、どうなるでしょうか?

答え:以下です。

my @aaa = ('aaa', 'bbb', 'ccc', 'ddd');
my $bbb = \@aaa;
print $#$bbb; # 配列リファレンスの場合は、こうなります。
print "\n";
for (my $i = 0; $i <= $#$bbb; $i++) {
        print $bbb->[$i], "\n";
}

2007-12-25 有難嬉悲しメモ(2007/12/25)


さて、どれが正解でしょうか?


って、もう、某教会へ行かないと…。

2007-12-24 有難嬉悲しメモ(2007/12/24)

2007-12-24 漢字クッキーをJavaScriptでSetしPerlでGetする!

クッキー出力で、IEのJavaScriptで漢字コードをescapeすると%uのあとにutf16be(4文字でビックエンディアン)になります。

尚、このURLエンコードですが、これは標準仕様でなく、MSの独自仕様です。

このクッキーをCGI(Perl)でデコードしてSJISにするサブルーチン(GetCookieForJavaScript)を作ってみました。


JavaScriptクッキー書き込みHTMLサンプル
<html>
<script type="text/javascript">
function SetCookie(){
         SetCookie.put = function(name ,data ,limit, domain, path) {
             var date = ''; 
             var wkdomain = ''; 
             var wkpath = ''; 
             if (limit) {
                 today = new Date();
                 today.setTime(today.getTime()+1000*60*60*24*limit);
                 date = ';expires='+today.toGMTString();
             }
             if (domain != '') {
                wkdomain='domain=' + domain + ';';
             }
             if(path != '') {
                wkpath='path=' + path + ';';
             }
             document.cookie = name + '=' + escape(data) + date + wkdomain + wkpath;
        }
}
new SetCookie();
//SetCookie.put:クッキー設定メソッド
//第1引数:クッキー名
//第2引数:データ(漢字OK)
//第3引数:有効期限(日にち単位で指定)
//第4引数:ドメインの値
//第5引数:パスの値
SetCookie.put("TEST_COOKIE","DATA1:1111あ,DATA2:やaaaす",1, "localhost", "/cgi-bin/");
</script>
<body>
<p><a href="../cgi-bin/cookie.cgi">クッキーテスト</a></p>
</body>
</html>


JavaScriptクッキー読み込みCGIプログラムサンプル
#!/usr/bin/perl -w
use strict;

my %COOKIE = &GetCookieForJavaScript("TEST_COOKIE");

print "Content-type: text/html; charset=Shift_JIS", "\n\n";
print <<"EOH";
<html>
<body>
<p>DATA1:$COOKIE{"DATA1"},DATA2:$COOKIE{"DATA2"}</p>
</body>
</html>
EOH

# クッキー取得サブ
sub GetCookieForJavaScript {
    my ($CookieName) = @_;
    my (%DUMMY, %COOKIE, $name, $value);
    my $cookies = $ENV{'HTTP_COOKIE'};
    my @pairs = split(/;/, $cookies);
    foreach my $pairs (@pairs) {
        $pairs =~ tr/+/ /; # URLでコード
        $pairs =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack('H2', $1)/eg; # URLでコード
       ($name, $value) = split(/=/, $pairs);
        $name =~ s/ //g;
        $DUMMY{$name} = $value;
        #debug($value);
    }
    @pairs = split(/,/, $DUMMY{"$CookieName"});
    foreach my $pairs (@pairs) {
        ($name, $value) = split(/:/, $pairs);
        $COOKIE{chgU2S($name)} = chgU2S($value);
    }
    return %COOKIE;
}

# ユニコード(utf16be)からシフトJIS(shiftjis)への変換サブ
sub chgU2S {
use Encode qw(from_to);
    my ($value) = @_;
    my $offset = 0;
    my $chgvalue = "";
    for (my $i = 0; $i < length($value); $i++) {
        my $wk = substr($value, $offset, 1);
        if (($wk eq "%") && (substr($value, $offset+1, 1) eq "u")) {
           $wk = pack('H4', substr($value, $offset+2, 4));
           from_to($wk, 'utf16be', 'shiftjis');
           $chgvalue  = $chgvalue . $wk;
           $offset = $offset + 6;
        }
        else {
           $chgvalue  = $chgvalue . $wk;
           $offset++;
        }
    }
    return $chgvalue;
}

補足:

クッキーは、セットしたドメイン&パスのところでしか、ゲットできません。

つまり、セットしたドメイン&パスとCGIが動くドメイン&パスが一致していなければなりません。

2007-12-23 有難嬉悲しメモ(2007/12/23)

補足

2人インフルエンザのもう一人は、昨日の有難嬉悲しメモ参照してください。

ママを連れてった病院は、『武蔵境クリニック』で日曜日も診療していていいですよ。ただし、車が4、5台ぐらいしかとめられない。

ヒロちゃん(長男)は、今、大学4年で、夜勤はアルバイトです。

2007-12-23 PerlでのURLエンコーディング

URLエンコーディング

URLエンコーディング(ユー・アール・エル・エンコーディング)、URLエンコード、パーセントエンコーディング

エンコーディング(エンコード)とは、データを特定のコードに変換することです。また、元に戻すことをデコーディング(デコード)と言います。

URLエンコーディングとは、URLに英字、数字、特定の記号(ピリオド、ハイフン、アンダースコア、チルダ)以外を指定する場合に、そのコードが特別な意味をもってしまうことを避けるために、16進数表現でエンコードする方式です。日本語の全角文字もエンコードの対象です。

エンコードの書式は「%nn」で、nnは16進数表現です。それで1バイトを表現します。たとえば「http://」は「http%3A%2F%2F」になります。

クエリー文字列内におけるスペース(半角空白)のエンコードは例外で、「+」に置き換えて表現します。

エンコードの16進数のアルファベットは大文字でも小文字でも構いません。

「URLエンコーディング」は、最新の規格(RFC3986)において「パーセントエンコーディング」と呼ばれます。

http://www.seiren-udoku.com/noteOfSeoMR-URL%E3%82%A8%E3%83%B3%E3%82%B3%E3%83%BC%E3%83%87%E3%82%A3%E3%83%B3%E3%82%B0.html
最新の規格(RFC3986 日本語訳)

http://www.studyinghttp.net/

に行って、以下のURLを入力

http://www.studyinghttp.net/cgi-bin/rfc.cgi?3986


上記を踏まえてコーディングすると・・・
URLエンコード
    $string =~ s/([^\w .-~])/'%'.unpack('H2', $1)/eg;
    $string =~ tr/ /+/;
URLデコード
    $string =~ tr/+/ /;
    $string =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack('H2', $1)/eg;

尚、フォームのエンコード方法は、以下の通りです。

フォームのエンコード方法はその中のRFC1866の第8.2.1節にあります。

スペースは '+' に置換する。

RFC1738(後述)で予約文字として定義されている文字はその16進数を%XX形式に変換する。

属性名と属性値はイコール"="で区切る。

レコード(属性名と属性値の2つ組み)はアンド"&"で区切る。

http://www.kinet.or.jp/hiromin/cgi_introduction/appendix/url_encode.html
RFC1866(日本語訳)

http://www.age.ne.jp/x/sf/HT/HTML/RFC1866J-1_0.TXT

2007-12-22 有難嬉悲しメモ(2007/12/22)

2007-12-22 動的に配列のハッシュを作る

たとえば、'aaa=111&bbb=222&bbb=333&bbb=444&ccc=555&ddd=666&ddd=777'という文字列があったとします。

これを入力データとして、以下のような普通のハッシュと配列のハッシュが混在したハッシュ(%FORM)を作ってみます。

$FORM{aaa}=111
$FORM{bbb}[0]=222     $FORM{bbb}[1]=333     $FORM{bbb}[2]=444
$FORM{ccc}=555
$FORM{ddd}[0]=666     $FORM{ddd}[1]=777
ソース(hh.pl)
use strict;
# 入力データ
my $buffer = 'aaa=111&bbb=222&bbb=333&bbb=444&ccc=555&ddd=666&ddd=777';

# ハッシュと配列のハッシュの混合ハッシュを作成する。
my %FORM = &hash_hairetu($buffer);

# 以下は上記のデータをプリントする。
foreach my $i (sort keys %FORM) {
    if (ref($FORM{$i}) eq "ARRAY") {
        for (my $j = 0; $j <= $#{$FORM{$i}}; $j++) {
            print '$FORM{' . $i . '}[' . $j . ']=' . $FORM{$i}[$j] . '     ';
        }
        print "\n";
    }
    else {
        print '$FORM{' . $i . '}=' . $FORM{$i} , "\n"
    }
};

#ハッシュの中が配列リファレンスだったらその配列データを返す。
my @data = hairetu_filter($FORM{bbb});
print '$#data=' . $#data . "\n";
for (my $i = 0; $i <= $#data; $i++) {
    print 'data[' . $i . ']=' . $data[$i], "\n";
}

#ハッシュの中がデータだったらそのデータを返す。
@data = hairetu_filter($FORM{aaa});
print '$#data=' . $#data . "\n";
for (my $i = 0; $i <= $#data; $i++) {
    print 'data[' . $i . ']=' . $data[$i], "\n";
}

# ハッシュの中が空だったら空を返す。
@data = hairetu_filter($FORM{xxx});
print '$#data=' . $#data . "\n";
for (my $i = 0; $i <= $#data; $i++) {
    print 'data[' . $i . ']=' . $data[$i], "\n";
}

# ハッシュと配列のハッシュを返すサブルーチン
sub hash_hairetu {
    my ($buffer) = @_;
    my ($name, $value);
    my %FORM = ();
    my @wk = ();
    my $i = 0;
    my @pairs = split(/&/, $buffer);
    foreach my $pair (@pairs) {
        ($name, $value) = split(/=/, $pair);
        if (exists $FORM{$name}) {
            if ($i == 0) {
                $wk[$i++] = $FORM{$name};
            }
            $wk[$i++] = $value;
            $FORM{$name} = [ @wk ];
        }
        else {
            $i = 0;
            @wk = ();
            $FORM{$name} = $value;
        }
    }
    return %FORM;
}

# ハッシュの中が配列リファレンスだったらその配列データを返すサブルーチン
sub hairetu_filter {
    my ($para) = @_;
    my @wk = ();
    if (ref($para) eq "ARRAY") {
        @wk = @$para;
    }
    elsif (defined($para)) {
        $wk[0] = $para;
    }
    return @wk; 
}
出力プリント
C:\test>perl hh.pl
$FORM{aaa}=111
$FORM{bbb}[0]=222     $FORM{bbb}[1]=333     $FORM{bbb}[2]=444
$FORM{ccc}=555
$FORM{ddd}[0]=666     $FORM{ddd}[1]=777
$#data=2
data[0]=222
data[1]=333
data[2]=444
$#data=0
data[0]=111
$#data=-1
ポイント解説

$FORM{$name} = [ @wk ];は、ハッシュに配列(@wk)のデータを無名配列コンストラクタを使用してそのリファレンスを格納する。

if (exists $FORM{$name}) { は、ハッシュキーが存在するかを判定する。

if (ref($para) eq "ARRAY") { は、ハッシュの要素が配列リファレンスかを判定する。

2007-12-21 有難嬉悲しメモ(2007/12/21)

2007-12-20 有難嬉悲しメモ(2007/12/20)

2007-12-20 配列リファレンスから他の配列へデータを移す

スカラー変数に配列リファレンスが格納されているときに、それを他の配列へ代入する。

my @tmp = ("aaa", "bbb", "ccc", "ddd");
my $para = \@tmp;
my @wk = @$para; # 配列代入
print @wk, "\n";
for (my $i = 0; $i <= $#wk; $i++) {
 print $wk[$i], "\n";
}

結果的には、配列をリファレンスして、デリファレンスして、配列代入しているだけです。

2007-12-19 有難嬉悲しメモ(2007/12/19)

補足:

前担当者の女の子、ガッキーを25、6才にした感じの素敵な子です。

2007-12-19 Win32::OLE->newメソッドのデストラクタについて

Win32::OLEモジュールのnewメソッドの第二引数は、デストラクタを指定します。

ちなみに、デストラクタとは、オブジェクトが破棄される直前に実行される処理です。

これはCODEリファレンスまたはOLEメソッド名の入った文字列のどちらかにすることができます。

http://perldoc.jp/docs/modules/libwin32-0.26/Win32/OLE.pod

とのことで、以下はどちらでもOKです。

# 第二引数にCODEリファレンスを渡す。
$excel = Win32::OLE->new('Excel.Application', sub {$_[0]->Quit;});

# 第二引数にOLEメソッド名の入った文字列を渡す。
$excel = Win32::OLE->new('Excel.Application', 'Quit');

# 自分で終了処理の関数を作って、そのCODEリファレンスを渡すこともOKです。
$excel = Win32::OLE->new('Excel.Application', \&subSelfFuc);
補足:

sub {$_[0]->Quit;}は、無名サブルーチンリファレンスで、$_[0]は、オブジェクト自身です。

したがって、sub {$_[0]->Quit;}は、Quitメソッドを起動しているのと等価です。たぶん。

補足2:

EXCELをプログラムから起動し制御すると、プロセスが残ることがあります。

デストラクタを指定することにより、Perlプログラムが不意に死んだ時にも、EXCELが適切に終了されることを保証します。

2007-12-18 有難嬉悲しメモ(2007/12/18)

2007-12-18 レキシカル変数の消滅タイミング

普通、レキシカル変数はレキシカルスコープを抜けると消滅します。

しかし、リファレンスの参照が残っていると消滅しない。

my $xxx;
{
    my $data = ('aaa, bbb, ccc');
    my $data2 = ('xxx, yyy, zzz');
    print $data, "\n";
    print $data2, "\n";
    $xxx = \$data;
}
# $data2は消滅する。しかし、$dataは$xxxに参照があるので消滅しない。
print $$xxx, "\n"; #aaa, bbb, ccc を表示
$xxx = undef; #これで$dataは消滅し、ガベージコレクションの対象となるらしい。

2007-12-17 有難嬉悲しメモ(2007/12/17)

2007-12-16 index/rindexとsubstr

正規表現での置換が得意になるとあまり使わなくなる、しかし基本のindex/rindexとsubstrです。


indexとrindexは、全文字列中に検索部分文字列を探し、あった場合は0オリジンでオフセットを返します。

indexとrindexの違いは、先頭から検索するか後尾から検索するかの違いです。

尚、後尾から検索した場合でも、オフセットは先頭からになります。


substrは、全文字列中をオフセットから指定長分を取得したり、それを置換文字列で置換したりします。

ただし、index/rindexとsubstrは、ともに正規表現は使えない。

$string = 'abc123dfghijklmnopqrstuvw123';
$substring = '123';
$replace = 'xyz';
$pos = rindex($string, $substring); # $posは、25で、後ろの123にマッチ
substr($string, $pos,length($substring)) = $replace;
print $string, "\n"; #abc123dfghijklmnopqrstuvwxyzを表示

2007-12-16有難嬉悲しメモ

新しいカテゴリーをスタートさせます。

名づけて有難嬉悲しメモ(ありがたうれしかなしメモ)です。

内容は、その日の一日で、『有り難かったこと』、『嬉しかったこと』、『悲しかったこと』をメモします。

文の最後を『有り難かったです。』『嬉しかったです。』『悲しかったです。』で締め括ります。

長く続けるのが目的なので、文は簡素で行きます。

2007-12-15 正規表現のメタ文字のエスケープ

正規表現でパターンマッチさせる時に、どの文字をエスケープするか、しないかが、分からなくなることがありますね。

エスケープする文字をメタ文字といい、各々以下の意味があり、その文字自体にマッチさせるには、前に『\』を添えます。

$string = '.*+?^$\|(){}';
$string =~ s/\*\.\+\?\^\$\\\|\(\)\{\}/match/;
print $string, "\n"; # match表示

ちなみに、以下の文字はエスケープ不要です。

$string = "\"',#%&!=~";
$string =~ s/"',#%&!=~/match/;
print $string, "\n"; # match表示

2007-12-14 キーとデータの別々のリストからハッシュを作る

一対一に対応しているキーとデータの別々のリストあったとします。

それらのリストで、簡単にハッシュを作ることができます(3ケース)。

my @key = ("aaa", "bbb", "ccc");  # キーリスト
my @data = ("111", "222", "333"); # データリスト
my (%d, %e, %f);

# ケース1
@d{@key} = @data;
print $d{aaa}, $d{bbb}, $d{ccc}, "\n"; #111222333表示

# ケース2
@e{@key} = ("111", "222", "333");
print $e{aaa}, $e{bbb}, $e{ccc}, "\n"; #111222333表示

# ケース3
@f{"aaa", "bbb", "ccc"} = ("111", "222", "333");
print $f{aaa}, $f{bbb}, $f{ccc}, "\n"; #111222333表示

注目は、d,e,fに各々『%』『@』『$』が先頭に付いて三変化しています。

2007-12-13 PerlでTrimする!

VB系では、文字列の両端にあるスペースを削除するに有名なTrimがあります。

しかし、Perlでは、残念ながらTrimはありませんが、以下の正規表現で一発です。

$string =~ s/^\s+(.*?)\s+$/$1/;

ちょっと解説です。

また、正規表現で二発でもよいと思います。

$string =~ s/^\s+//;
$string =~ s/\s+$//;

2007-12-12 pack関数とunpack関数の基本を理解する

一般的に、packは包み込むことで、unpackはその逆です。


Perlでのpack関数は、リスト値を型指定で包み込んで、バイナリ値に変換します。unpack関数はその逆です。


バイナリ値とは、たとえば、見た目『123』は、内部的には16進の『313233』で、バイナリ値です。

つぎに、リスト値『313233』を16進上位ニブル型指定("H*")でパックしてみます。

すると、見た目バイナリ値が『123』になるのです。

print pack("H*", 313233); #内部的には16進の『313233』である見た目バイナリ値『123』が表示される

つぎに、見た目バイナリ値『123』を16進上位ニブル型指定("H*")でアンパックしてみます。

すると、リスト値『313233』が表示されます。

print unpack("H*", 123); #リスト値『313233』が表示される

尚、16進上位ニブル型指定("H*")とは、16進数で左から4ビットずつ変換すること。

ちなにみ、ニブルとは、4ビットのことで、8ビットをバイトと呼ぶのと同じ感じです。


別の例として、符号なしchar型指定("C*")で『65,66,67』のリストをパックしてみます。

すると、見た目バイナリ値『ABC』が表示されます。

print pack("C*", 65,66,67); # 見た目バイナリ値『ABC』が表示される

見た目バイナリ値『ABC』をアンパックすると元のリストが求められる。

@aaa = unpack("C*", pack("C*", 65,66,67));
print $aaa[0], "\n"; # リスト値『65』が表示される
print $aaa[1], "\n"; # リスト値『66』が表示される
print $aaa[2], "\n"; # リスト値『67』が表示される

2007-12-11 tr変換演算子のテストメモ

置換はイメージしやすいのですが、変換は思わぬ結果になる場合が多いですね。

以下にtr変換演算子のテストメモをしときます。

#1文字ずつ対応して変換(ケース1)
$string = 'aaaa,bbbb,cccc';
$string =~ tr/abc/xyz/;
print $string, "\n"; # xxxx,yyyy,zzzz が表示される
#
#1文字ずつ対応して変換(ケース2)
$string = 'aaaa,bbbb,cccc';
$string =~ tr/ac/xz/;
print $string, "\n"; # xxxx,bbbb,zzzz が表示される
#
#検索文字リストが多い場合(検索文字リストのcはyと対応する)
$string = 'aaaa,bbbb,cccc';
$string =~ tr/abc/xy/;
print $string, "\n"; # xxxx,yyyy,yyyy が表示される
#
#変換文字リストが多い場合(変換文字リストのzは無視)
$string = 'aaaa,bbbb,cccc';
$string =~ tr/ab/xyz/;
print $string, "\n"; # xxxx,yyyy,cccc が表示される
#
#s修飾子使用の場合(連続文字が一つにまとめられて変換)
$string = 'aaaa,bbbb,cccc';
$string =~ tr/abc/xyz/s;
print $string, "\n"; # x,y,y が表示される
#
#c修飾子使用の場合(検索文字リストに含まれない『,』が変換対象になる)
$string = 'aaaa,bbbb,cccc';
$string =~ tr/abc/:/c;
print $string, "\n"; # aaaa:bbbb:cccc が表示される
#
#c修飾子とd修飾子使用の場合(検索文字リストに含まれない『,』を削除)
$string = 'aaaa,bbbb,cccc';
$string =~ tr/abc/:/cd;
print $string, "\n"; # aaaabbbbcccc が表示される

2007-12-10 リバース(reverse関数)の意外な使い道

reverse関数は、リスト(リストコンテキスト)や文字列(スカラーコンテキスト)を逆並びにします。

そして、意外な使い道とは……。


たとえば、文字列の後尾の方にマッチしたいパターンがあったとします。

正規表現では、最大マッチと最小マッチがあり、最小マッチはある意味、先頭マッチです。

そう、後尾マッチがないのです。

そこで、reverse関数を使って逆並びにし、最小マッチさせるのです。


その後、再度reverse関数で元に戻します。

するとあたかも、後尾マッチが出来たことになるのです。

2007-12-09 仏教誕生の日(成道会)

昨日は12月8日、仏教誕生の日で、そのイベントでいろいろ忙しく、日記をお休みしました。


今から約2500年前、今のインド周辺のカピラバストという国の王子で、シャーキャ族(釈迦族)の聖者(牟尼)、『世に比類なき尊いお方』のバガヴァン(世尊)である釈迦牟尼世尊が修行の末、35歳の時、明けの明星が輝く12月8日の朝、ついにお悟りを開かれたのです。

『お悟りを開いた人(真理を悟った人)』のことを梵語(サンスクリット)で仏陀(ブッタ)と云い、なので釈迦牟尼世尊は仏陀と呼ばれ、日本では、訓読みで『仏さま』と呼ばれるようになりました。


そう、これこそが、どんな困難も克服することのできる智慧と慈悲の仏教誕生の瞬間でありました。

2007-12-09 フォルダ内ファイル一括修正プログラムの雛型

たとえば、フォルダ内に沢山のhtmファイルがあったとします。

全htmファイルのh4要素(h4タグ)をh3要素(h3タグ)に一括変更するには、以下の感じです。

$/ = undef; # ファイル全体を読み込むためにレコード区切り文字デリミタを未定義にする
while ($fileName = glob("VBMemo*.htm")) {
    open(FH, "<$fileName") or die "open error1 ($!)";
    $fileBody = <FH>; # ファイル全体を読み込む
    close(FH);

    $fileBody =~ s/<h4/<h3/g;
    $fileBody =~ s/<\/h4/<\/h3/g;

    open(FH, ">$fileName") or die "open error2 ($!)";
    print FH $fileBody; # ファイル全体を書き込む
    close(FH);
}

上記プログラムにおいて、フォルダ内ファイル一括変更で、以下の2点を調整すれば、いろいろ応用が利くはずです。


留意点

ファイルそのものを置き換えますので、万が一を考えて、ファルダを一時的にどこかへコピーしてから、上記プログラムを実行してください。万が一のときは、そこからロールバックしてください。

2007-12-07 クッキーCGIサンプル

クッキーは、Webサイトのセッション管理や前回入力値の再入力不要を実現するのに使います。

以下のようなサンプルを作ってみました。URLエンコードデコードにも対応しています。

# セットクッキー:第一引数はクッキー名、第二引数は格納データ、第三引数はクッキー有効期間(日単位)
&SetCookie("CookieName", "aaa:111,bbb:あいう", 1);


# ゲットクッキー:第一引数はクッキー名
my %COOKIE = &GetCookie("CookieName");
print "Content-type: text/html; charset=Shift_JIS", "\n\n";
print <<"EOH";
<html>
<body>
<p>aaa:$COOKIE{"aaa"},bbb:$COOKIE{"bbb"}</a>
</body>
</html>
EOH


sub SetCookie {
    my ($CookieName, $cookies, $daycount) = @_;
    my ($secg,$ming,$hourg,$mdayg,$mong,$yearg,$wdayg) = gmtime(time + $daycount*24*60*60);
    my @week = ('Sun','Mon','Tue','Wed','Thu','Fri','Sat');
    my @mons = ('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec');
    my $date_g = sprintf("%s, %02d\-%s\-%04d %02d:%02d:%02d GMT",
       $week[$wdayg],$mdayg,$mons[$mong],$yearg+1900,$hourg,$ming,$secg);
    $cookies =~ s/([^\w .-~])/'%'.unpack('H2', $1)/eg;  # URLエンコード
    $cookies =~ tr/ /+/;  # URLエンコード
    print "Set-Cookie: $CookieName=$cookies; expires=$date_g\n";
}
sub GetCookie {
    my ($CookieName) = @_;
    my (%DUMMY, %COOKIE, $name, $value);
    my $cookies = $ENV{'HTTP_COOKIE'};
    my @pairs = split(/;/, $cookies);
    foreach my $pairs (@pairs) {
        ($name, $value) = split(/=/, $pairs);
        $name =~ s/ //g;
        $DUMMY{$name} = $value;
    }
    @pairs = split(/,/, $DUMMY{"$CookieName"});
    foreach my $pairs (@pairs) {
        $pairs =~ tr/+/ /; # URLでコード
        $pairs =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack('H2', $1)/eg; # URLでコード
        ($name, $value) = split(/:/, $pairs);
        $COOKIE{$name} = $value;
    }
    return %COOKIE;
}

(尚、本サンプルは、KENT-WEBのfantasy.cgiをベースにしています)


プログラムの制限として

クッキーの制限として

参考:http://www.studyinghttp.net/cookies


クッキーの補足として

サンプルでは使っていませんが、path属性とdomain属性を指定すると別サーバーや複数サーバーへクッキーを送信することが出来ます。

逆にこれを指定しない場合は、PCクライアントとCGIサーバー間でのクッキー送受信になります。


URLエンコードの補足として

インターネット初期ではアスキー文字(7bit)が標準で、それ意外は文字化けする可能性があったので、以下のようにエンコードするようになった。

A〜Z a〜z 0〜9 - . _ はそのまま。

半角スペースは + に変換。

その他はすべて % に16進の2桁の文字コード。

たとえば、「あ」0x2422なら %24%22になる。

ちなみに、URLデコードは、URLエンコードしたものから元にもどすこと。

2007-12-06 JavaScriptにフォーム部品情報を渡すには

input要素でonClickした時にJavaScriptへフォーム部品情報渡すには・・・。

とりあえず、以下の3と通りがありますね。

  1. thisで自分自身のオブジェクトを渡す方法
  2. name属性の値を渡す方法
  3. id属性の値を渡す方法
<html>
<head>
<script type="text/javascript">
function CheckThis(obj) {
        alert(obj.id + " " + obj.name);
        obj.checked = false;
        alert("チェックできません!(thisで自分自身のオブジェクトを渡す方法)");
}
function CheckName(name) {
        alert(name);
        document.FM.elements[name].checked = false;
        alert("チェックできません!(name属性の値を渡す方法)");
}
function CheckId(id) {
        alert(id);
        document.getElementById(id).checked = false;
        alert("チェックできません!(id属性の値を渡す方法)");
}
</script>
</head>
<body>
<form name="FM">
<input type="checkbox" name="AAA" id="AAA" onClick="CheckThis(this)">A</input>
<input type="checkbox" name="BBB"          onClick="CheckName(name)">B</input>
<input type="checkbox" name="CCC"          onClick="CheckName('CCC')">C</input>
<input type="checkbox"            id="DDD" onClick="CheckId(id)">D</input>
<input type="checkbox"            id="EEE" onClick="CheckId('EEE')">E</input>
</form>
</body>
</html>

2007-12-05 リファラ(HTTP_REFERRER)がスルーする

リファラは、CGIの環境変数(HTTP_REFERRER)の一つで、普通、1つ前のページのURLが格納されています。

しかし、自動ジャンプページを挟むと、このページはスルーされて、2つ前のページのURLが格納されてしまいます。

つまり、自動ジャンプページのリファラが取得できないのです。

ここで云う、自動ジャンプページとは、以下の3通りのページです。

また、CGI-URL直打ち、や「お気に入り」からのCGI-URL指定では、リファラがヌルで取得ができませんし、フレームにすると親フレームのリファラになりますね(ある意味当然)。

なので、WEBサイトのセッション管理では、リファラは使えない。

しかも、リファラでは、期間管理もできないし、やはり、セッション管理はクッキーですね。

2007-12-04 Perlでm演算子と正規表現の記憶

m演算子は、文字列中の正規表現検索だけでなく、正規表現にマッチした文字列も取得することができます。

たとえば、以下では、小括弧中の正規表現『.*』にマッチした文字列が $1 へ代入され、つぎの右の小括弧2つは、同じくマッチした文字列が各々 $2 と $3 に格納される。

my $aaa = "111,222,333, 444,555";
$aaa =~ m/^(.*), (...),(5+)$/;
my @aaa = split(",", $1);
print $aaa[0], "\n"; # 111が表示
print $aaa[1], "\n"; # 222が表示
print $aaa[2], "\n"; # 333が表示
print $2, "\n"; # 444が表示
print $3, "\n"; # 555が表示

もう、$aaaと$aaa[0]の違いは分かるよね!

2007-12-03 やさしく肯くことからはじめよう

相手の気持ちという音源に、自分の心の音叉を共鳴させながら、そっと肯く。

http://blogs.yahoo.co.jp/hyuki0000/27693302.html

このお言葉、私の心の音叉も共鳴しました。名文だと思います。

2007-12-03 Perlで文字列長(バイト数)を求めるには

length関数で文字列長のバイト数を取得することができます。

$aaa = "abcdefghijklmnopqrstuvwxyz";
print length $aaa, "\n"; # 26が表示される

尚、length関数は、文字数でなく、漢字コードに関係なく、バイト数を返します。




kitsさん、simpleboxesさん、いろいろご指摘、ありがとうございます。

咀嚼して、コンテンツに反映させていただきます。

2007-12-02 よかった探しリース2007

今年は、昨年、一昨年と比べれば、天国のような一年でした。

昨年、一昨年は、父の葬式と介護で本当に大変でした。


[よかった探し]
  1. 家族が皆、元気に暮らせて、よかったよかった。
  2. 家内の鬱病は、大分よくなって、家のことも出来るように復活しつつあるので、よかったよかった。
  3. 次男の大学入学金がどうしても捻出できないことがわかり、本人が部活(バスケ)をやめてバイトをしはじめたけど、思わぬ収入があり、部活に復帰、よかったよかった。
  4. 仕事が得意なWEB系になったので、よかったよかった。

とにかく、毎日、普通に暮らせることが、実は、すごく幸せなことなのだな・・・と思える今日この頃です。

2007-12-02 燈明日記11月分更新

2007-12-01 教会へ行く

今日は、布薩の日で、一日参りといって、朝から教会へ行きました。

毎月一日は、佼成ニュースとスマイルのサテライト教会へ行く

司会の女の子が大阪教会の藤元沙友里さんといって、とても可愛かったです。

ちゃいちゃんが生きていれば丁度同じぐらいの年頃で名も同じで・・・・・・。


スマイル(会員ドキュメント)は、ひと月の半分近く奄美諸島を船で布教する会員さん達のドキュメントでした。

そのドキュメントの中で支部長さんという中年のおばさんの以下のお言葉が印象的でした。

私は、このすばらしい教え(法華経)を一人でも多くお伝えすることだけを考えて生きてきました。生きがいなんて考えたことがないです。』

おぉ、すばらしい! そして、船で困難な布教だけれど、すごく幸せな人なんだなと思いました。


生きがいを考えたことがないほど、夢中で生きられる人生・・・すばらしい!