iso tank - プログラムな?話 2007年

パイソンPython

相変わらずいつなんどき何に興味が向くかわけのわからないワタクシ。また最近になってPythonに興味わいてきた。

で、今は何してるかっていうとついさっきまでURLエンコーディングについて考えてた。 URLエンコーディングっていうのはほら、よくWIKIとかGOOGLEとかの類にあるURLの後ろに"%"と英数字がいっぱいついてるやつ。あれのことなんです。 あれは2バイト文字をサーバとかそういうのが解釈できるように符号化したもので、「URLエンコード」でググると、簡単にURLエンコーディングができるサイトがぼろぼろ出てくるです。 でまぁ、Pythonでもできるのかなーってふと気になった。やってみた。ちょっと1週間近くつまづいた挙句にぱっと閃いたら30分くらいで完成した。

http://iso.tank.jp/sandbox/py/urlende.cgiで、エンコードしたい文字列を入力して文字コードを選んで送信すればいいです。 その文字コードで変換したわけのわからない文字列があなたを出迎えてくれます。逆にわけのわからない文字列をわけのわかる普通の単語に戻す(デコードする)こともできます。 この時、変換元の文字コードがわからないとエラーを吐き出すので注意。

エンコードは一行で済んだ。なんかある意味すごいわ。でもUnicodeの扱い方がちょっとよくわからなくて混乱した。

文字列 = urllib.quote_plus(unicode(文字列,'utf-8').encode(文字エンコード),':;/')

urllibっていうのがモジュール。quote_plusっていうのがurllibモジュールについてる関数。unicodeは標準でついてる関数。encodeはメソッド。 あ、日本語のところには変数がはいります。quote_plusの第二引数":;/"はエンコードしない記号。仕様は、 「入力されたUTF-8の文字列をUnicode化し、できあがったそれをユーザーお好みの文字コードに変換し、それをURLエンコードしちゃいなさい?」 となるです。もしUTF-8以外の文字列が入力されると多分エラーを吐き出すかも。HTMLそのものがUTF-8で作られてるから、入力される文字もUTF-8じゃないとおかしいんだけどぬー。

デコードはこう。

文字列 = unicode(urllib.unquote_plus(文字列),文字エンコード).encode('utf-8')

「入力されたURLエンコードされているはずの文字列を普通の文字列に直して、できあがったお好みの文字コードで構成されているはずの文字列をUnicode化し、それをUTF-8に変換しなさい?」 という仕様。だいたい。エンコードもデコードも「はず」という前提で動いてるから、あまり無茶はしてやれない。っていうかデコードも一行で済んでますね。色々すっ飛ばしてるからね。

で、要所要所にちりばめられている「unicode」。まずは、「Unicode」と「UTF-8」は"違うもの"ということを理解する必要があるようです。 よくはわからないけどUnicodeというのは文字コード表そのもの、つまり「文字コード本体」のことで、UTF-8というのは「符号化方式」えーとつまり「変換方法」のこと、みたいな。 結局どういうことかといえば、ある文字コードから他の文字コードに変換したりするのに、いったんUnicode表記にしないと他の文字コードに変換できないっぽいらしいということ。

ENCODE: UTF-8→Unicode→お好み→URL文字列
DECODE: URL文字列→お好み→Unicode→UTF-8

こゆこと。

あと、Pythonは標準でエラー処理について色々と充実している。っぽい。

try:
    文字列 = unicode(urllib.unquote_plus(文字列),符号化方式).encode('utf-8')
except UnicodeError:
    メッセージ = "文字列変換誤り。正しひ符号化方式を指定下さるやう。"

TRY節を実行して、exceptにあるエラー(この場合はUnicodeErrorというエラー)が発生した場合はEXCEPT節を実行する。EXCEPT節はいくらでもいっぱいつくれる。っぽい。 この文の後ろに

except:
    メッセージ = "何だか解りませんが、兎に角御免なさい。"

と書いておくと、UnicodeError以外のエラーは全部このように処理されるという仕組み。うーん面白い。

そんなわけで、http://iso.tank.jp/sandbox/py/urlende.cgiでなんか変なエラーとかでたら教えてほしいのです。よろしく。

2009/12/24追記 URL変えてました。忘れてた。

スコープとマッチの罠

以前、後方参照やらの動作で悩んでいた問題 について、一定以上の理解を得た。

なんか長くなった気がするので気になる人は続きを読むで読んでください。

これは「スコープ」と呼ばれる動作が原因らしい。スコープとは?  もちろん望遠鏡のことである。が、この場合「見える範囲」といった意訳がしっくりくるかもしれない。 プログラミングにおいてはとても重要な概念である。プログラミングに重要、ということは、 ソフトやOS、ひいてはパソコンにとって重要ということである。俺見落としてた。

では具体的にどういうものなのか。スコープには「動的スコープ」と「静的スコープ」があるが、 動的スコープは説明が難しいし今回はあまり関係ないようなので、 静的スコープ(レキシカルスコープ・lexical scope)だけ説明する。勘のいい読者なら 「動く望遠鏡と動かない望遠鏡がある、つまり見える範囲が動くものとそうでないものがある」 というところまで気づいていると思う。そのとおり。 レキシカルスコープとは、見える範囲が常に一定であることを指す。

例えば、大きく複雑なプログラムAがあるとして、その中にさらに小さくかつ単純なプログラム A年1組~A年10組がある。1組のプログラムは、さらに小さくかつ単純な1班~10班で 構成されている。プログラムとは往々にしてこのような階層構造(ツリー構造)になっている。

で、例えばA年5組が「5組の平均点は500点」という情報を持っていたとする。 A年5組のテストの平均点が500点であることは、1班~10班の誰もが知ることである。 しかし例えばここで8班の内部情報として「8班の吉田さんのバストはCカップ」という 情報を持っていたとする。8班の人間は、5組のテストの平均点が500点であることも、 吉田さんがCカップであることも知っている。しかし「8班の吉田さんはCカップ」 という情報は、他の班の班員は知り得ない。また5組全体としても知り得ない。

これがプログラミングにおけるレキシカルスコープ(の範囲)である。 これをコードにするとおおむねこういうことになる。


program A年生:
  5組 {
    my $平均点 = 500;
      8班 {
        my $吉田さんのバスト = Cカップ;
      }
  }

ちょっとめんどくさいだろうか。つまり5組プログラムの中における8班プログラムの 情報値は、それより外部のプログラムは取得できないようになっている。これは絶対である。 逆に、5組プログラムの情報値を、その下位プログラムは何の問題もなく取得できる。 このように、プログラムを階層構造にするだけでそのルール付けを決定できることから、 「構文スコープ」という呼ばれ方もする。らしい。

さて、次は「マッチ」についてである。まず先に言っておくと、近藤真彦のことではない。 マッチ違う。ここだけはおさえておかなくてはならない。 マッチとは、ある値が一定の条件内において一致するかどうか、という条件分岐を行う式である。 例えば「近藤マチャ彦」という単語があるとして、この単語の中に「マッチ」という語句が含まれているか、 そういった判定を行ったり、あるいは語句を置き換えることができる。


$A = "近藤マチャ彦";    #変数Aに「近藤マチャ彦」を代入
if ($A =~ /マッチ/) {   #この括弧内の式が「マッチ式」と呼ばれる
  print "あります!";   #あれば、「あります!」と出力
} else {
  print "ありません!"; #なければ「ありません!」と出力
}                       #結果は「ありません!」

特にPerlは文字に強いプログラミング言語である(と思っている)。 例えば「近藤真彦」の「真」の字を探し出して「真」を「マチャ」に置き換えることなど造作もない。


$A = "近藤真彦";
$A =~ s/真/マチャ/;  #ここがマッチ式。「真」を「マチャ」に置き換える
print $A;            #結果は「近藤マチャ彦」

「正規表現」と呼ばれる、特殊な記号を用いた表現を利用することで、さらに広範な利用が可能だ。 この「正規表現」には様々な機能があるが、以下は無駄な単語の連続を削除することができる。


$コメント = "あらしだよーんああああああああああああしねしねしねしねしねしねしね";
# 荒らし書き込みがあったとする
$コメント =~ s/あ{5,}//g;      #「あ」が5回以上連続で書かれていたら消去
$コメント =~ s/(しね){2,}//g;  #「しね」が2回以上連続で書かれていたら消去
print $コメント;               #結果は「あらしだよーん」

実際にはこんなピンポイントな荒らし対策がとれるわけないが、こういった用途に使うことも出来る。

で、正規表現には「マッチした単語を覚えておく」という機能がある。これが 以前に書いた「後方参照」あるいは「グループ化」と呼ばれるものだ。 マッチ式の中でカッコ書きされた内側のマッチ式に一致した単語は、特殊な変数域に記憶され、任意に呼び出すことができる。


$A = "近藤マチャ彦";
$A =~ /近藤(.*?)彦/;  #「近藤」と「彦」の間の語句が記憶される。
$B = "$1$1";          #$1という特殊な変数に記憶されている。
print "$Bで~す!";   #結果は「マチャマチャで~す!」

マチャ彦も早変わりである。

で、

簡単に言うとこの「後方参照」の機能に俺の予期しない動作があった。 マッチを2回以上行ったとき、例えば1回目のマッチで一致し$1に単語が記憶されていて、 2回目のマッチで一致する語句がなかった場合、$1は空にならず1回目のマッチの結果が残っている。


$A = "近藤真彦";
$B = "新田純一";
$A = ~/近藤(*.?)彦/;          #$1に「真」が入る
print "\$1の中身は「$1」\n";  #結果は「$1の中身は「真」」
$B = ~/近藤(*.?)彦/;          #マッチしない
print "\$1の中身は「$1」\n";  #結果は「$1の中身は「真」」

そんなこんなでようやく俺は理解したのだった。以上終わり

危機は脱した

今日のみつを

いいことは、おかげさま

わるいことは 身から出たさび

確かに「HP作ってよビーム」を受けておきながら半年以上放っておいたのはまずかった。 先方カンカンであった。皮肉を連発されたが全部パリィしておいた。よけい怒ってた気がする。 「画像とかあげるからTOPだけでも作ってもらわないと」何、まだ俺に作らせるつもりか。 というか俺はHTML書けるけどデザインなどさっぱりわからんと何度言ったら。 俺は先方にこのサイト(iso tank)を見せたことはない。

仕方ないから画像もらい次第スキャンしまくって画像結合しまくって「完成」とする所存。

「ねぇ、HPつくってよ」

今日のみつを

つまづいたっていいじゃないか 人間だもの

と、いうわけで実はとてもピンチなわたし。半年ほど前からHP作ってよと某団体の方々から 依頼されているのですが、俺はウェブデザイナーでもデザイナーでも絵心のある人間でもない。 というかたたき台くらいほしいデス。どんなことを伝えるサイトなのか? 目的、目標は? 趣味 特技?

はい、そこを含めて作れってことですか。こ、困ったな。ていうか正直、やる気が全然 出ないんですよ・・・。なんせそうそう無いジャンルだし、例えばテンプレートだとか、 参考になるサイトだとか、そういうのないんすよ。うあ、どうしよ。そもそも俺、HPを作るための イロハすら知らないんすよ。何から始めればいいの? 宇宙はどこから始まったの?

OK。ときに落ち着け俺。俺はやればできる子、俺はやればできる子、 俺はやればできる子・・・。そう心に言い聞かせ、落ち着いてフローを立ててみる。

まず第一に必要なのはサイトの目的とか目標とか、方向性とか。じゃないかな。至上にして 最終の目的は「自分たちの団体の存在を世に広く知っていただき、支援者ひいては加入者を 増加させることによる利益の向上とか人気の向上」、こんなところだろうか。

次はコンセプト、いわゆる概念というやつだ。この場合、この某団体のコンセプトではなく いわゆるサイトコンセプトのことであろう。多分。思考。思考。このサイトは某団体が運営する、 某団体の某活動を広く知ってもらう為のサイトとなる。つまり広告塔的な役割を果たす。

となるとコンテンツの内容は基本的に某団体の活動紹介のみになるんじゃないか?  と思ったら、某団体によると動画配信も予定しているらしい。それならキラーコンテンツは コレ(動画配信)になる。

  • お知らせ(更新情報や活動案内?)
  • 某団体の紹介
  • 年間スケジュール
  • 活動時動画・画像の配信(ここがメインになると予想)

コンテンツはこんな感じか。面倒そうなものは排除。排除。日記とかリンクとかBBSとか いらんだろ。

あとはデザイン・レイアウトだな。ここが一番ひどい。 なにせ俺にはそんなスキルもなければ、某団体の素材が少なすぎるのだ。HTMLの構造化うにゃらら とかなら胸のホクロに毛が生えた程度に自信はあるしできないことはないけど、このサイトは そういうことはどうでもいいわけで。

というか俺がつまづいているのがまさにココ。さてどうしたものか。というか正直に言う。 これ明日まで何某かを出さなきゃならないんすよ。業務じゃないのに追われてる。 まじボスケテ。俺はじけそう。

なお俺の通称はキョンではないし某団体の略称がSOSうんたらとかいうのではないということは ここに明言しておく。俺はキョンじゃない。

後方参照のおべんきょう

実験その1:


  do {
      while (my $line = shift(@hairetsu)) {
        $line =~ /(PATTERN2)-(PATTERN3)/;
        $tmp = "$1, $2\n";
      }
    }
  } while ($p =~ s/(PATTERN1)//);
  print $tmp;

Whileの条件文内でパターンマッチ、doブロック内でもパターンマッチをして、 両方ともに()をつけてグループ化(後方参照)してみた。簡単にいうと。

結果:


PATTERN1,
PATTERN2,PATTERN3,
PATTERN2,
PATTERN1,
PATTERN1,
PATTERN2,
PATTERN1,
PATTERN1,
PATTERN2,
PATTERN1,
PATTERN1,
PATTERN2,
PATTERN1,
PATTERN1,

深層のwhileブロック内でマッチするパターンがあった場合は、正しくPATTERN2とPATTERN3を 出力してくれたが、PATTERN2もPATTERN3もマッチしなかった時はwhileの条件文でマッチした PATTERN1がどこからともなく呼び出されていた。ような。

深層のwhileブロックがループ開始戻った段階で$n(数字)の値は、毎回毎回最上層の while条件文でマッチした値に初期化されているとゆうか。

つまりこうすると、


  do {
      while (my $line = shift(@hairetsu)) {
        $tmp = "$1, $2\n";
        $line =~ /(PATTERN2)-(PATTERN3)/;
      }
    }
  } while ($p =~ s/(PATTERN1)//);
  print $tmp;

PATTERN1,しか出力しなくなるわけなんですよ。

こういった動作について言及してるサイトってないかなー?

#元のflavourdirの"while ($p =~ s/(\/*[^\/]*)$// and $1);" の意味がいまだによくわからない・・・これ別に後方参照しなくてもいいんじゃね?