メモ代わり。てきとーに。 いや、ですからてきとーですって。 2年前ぐらいにPythonあたりでメールくれた方、ごめんなさい。メール紛失してしまい無視した形になってしまいました。。。

2008年1月26日土曜日

[Python][お勉強] Python入門(6) - 文字列を理解する

最終目標

Pythonにおける文字列を理解する。

文字列

見ていくものは以下のとおり。

  1. 文字列リテラル
  2. エスケープシーケンス
  3. raw文字列
  4. トリプルクォーテーション
  5. Unicode文字列
  6. 基本的な演算子
  7. インデクシング
  8. スライシング
  9. 型の変換
  10. 文字列の変更
  11. 文字列フォーマット
  12. 文字列のメソッド

・・・結構ボリュームあり。

まず、文字列もオブジェクト

Pythonも文字列はひとつのオブジェクトとして扱う。
文字列はimmutableであるオブジェクトのひとつ。
文字列は「シーケンス」と呼ばれるオブジェクトの一種だそうで。



文字列リテラル

Pythonでは文字列を記述する方法がいくつかある。その方法を以下に記す。

1) シングルクォーテーション


$ python
Python 2.4.4 (#2, Apr 5 2007, 20:11:18)
[GCC 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> 'こんちは'
'\xe3\x81\x93\xe3\x82\x93\xe3\x81\xa1\xe3\x81\xaf'
>>> 'abc123'
'abc123'
>>>



日本語はバケバケだけど、こういうもの???
まぁいいや。後で調べるとして次いこう。


2) ダブルクォーテーション


$ python
Python 2.4.4 (#2, Apr 5 2007, 20:11:18)
[GCC 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> "だぶるくぉーてーしょんだよ"
'\xe3\x81\xa0\xe3\x81\xb6\xe3\x82\x8b\xe3\x81\x8f\xe3\x81\x89\xe3\x83\xbc\xe3\x81\xa6\xe3\x83\xbc\xe3\x81\x97\xe3\x82\x87\xe3\x82\x93\xe3\x81\xa0\xe3\x82\x88'
>>> "Hello,World"
'Hello,World'
>>>



ここで気になるところは、インタラクティブ環境では文字列の出力はシングルクォーテーションで
行われているということ。内部的にはシングルクォーテーションで保持しているということかもしれない。
また、Pythonではシングルクォーテーションとダブルクォーテーションは同じ扱いだそうで。
シングルクォーテーションや、ダブルクォーテーションを文字列の中に入れるときに便利。

例)

$ python
Python 2.4.4 (#2, Apr 5 2007, 20:11:18)
[GCC 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> "O'reilly"
"O'reilly"
>>> '"hello"'
'"hello"'
>>>



3) トリプルクォーテーション


$ python
Python 2.4.4 (#2, Apr 5 2007, 20:11:18)
[GCC 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> """あいうえお
... かきくけこ
... さしすせそ
... たちつてと"""
'\xa4\xa2\xa4\xa4\xa4\xa6\xa4\xa8\xa4\xaa\n\xa4\xab\xa4\xad\xa4\xaf\xa4\xb1\xa4\xb3\n\xa4\xb5\xa4\xb7\xa4\xb9\xa4\xbb\xa4\xbd\n\xa4\xbf\xa4\xc1\xa4\xc4\xa4\xc6\xa4\xc8'
>>> """GET / HTTP/1.0
... User-Agent: HOGEHOGE
... Host: www.google.com
... """
'GET / HTTP/1.0\nUser-Agent: HOGEHOGE\nHost: www.google.com\n'
>>>




変なクォーテーションだが、複数行からなる文字列を生成するときに便利。
この複数行からなる文字列を「ブロック文字列」と呼ぶらしい。


4) エスケープシーケンス

'\n'とか'\t'とか。

5) raw文字列

ファイルパスなんかを書くときに便利。

例)

$ python
Python 2.4.4 (#2, Apr 5 2007, 20:11:18)
[GCC 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> print r"C:\a\b\c"
C:\a\b\c
>>>



といった感じに書ける。raw文字列を使うとエスケープシーケンスが完全に無効になる。


6) Unicode文字列



>>> u'eggs\u0020spam'
u'eggs spam'
>>>



上記はスペースをUnicodeで記述した例。本によるとあんまり使用する機会が無いとのこと。



エスケープシーケンス

文字列の中にバイトコードを埋め込む場合に使用する。
たとえば、改行コード、タブコードを入れる場合など。


>>> print "abcdefg\naaaaaa\nbbbbbb\tccccc"
abcdefg
aaaaaa
bbbbbb ccccc
>>>



などなど。

で、エスケープシーケンスの一覧。
エスケープシーケンス意味
\改行行の継続
\\バックスラッシュ文字
\'シングルクォーテーション文字
\"ダブルクォーテーション文字
\aビープ音を鳴らす
\bバックスペース
\f改ページ
\n改行
\r復帰
\t水平タブ
\v垂直タブ
\N{id}Unicodeデータベース中でidに対応する文字
\uhhhh16ビット16進数値hhhhに対応するUnicode文字
\Uhhhh...32ビット16進数値hhhh...に対応するUnicode文字
\xhh16進数hhに対応するASCII文字
\ooo8進数oooに対応するASCII文字
\0NULL
\その他の文字エスケープシーケンスとしては扱われない






文字列の演算子

文字列を利用する演算子を列挙する。
演算子説明
=代入する
+連結
*繰り返し
s[i]インデクシング
s[i:j]スライシング
len(s)長さを取得する
%文字列フォーマット
.メソッド呼び出し
for x in sループ
'm' in s特定の文字が含まれているかの確認



代入は良いとして、+は連結に使われる。*はPerlで言うところのx演算子か。


>>> 'a' + 'b' # ←連結
'ab'
>>> 'a' * 100 # ←繰り返し
'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
>>> print 'あへ' * 10
あへあへあへあへあへあへあへあへあへあへ
>>>

ここまではだいたいわかった。
次は、in演算子。for文で使用する場合とfor文以外で使用する場合の2通りの使い方があるようだ。

for文で使う場合は、、

>>> myjob = "abcdefg"
>>> for c in myjob: print c
...
a
b
c
d
e
f
g



のように使うらしい。for文に使う場合は文字ひとつひとつを取り出す、というイメージ。
もうひとつが、

>>> "k" in myjob
False
>>> "c" in myjob
True
>>>



と、myjob変数の中の文字列に"k"という文字や"c"という文字が含まれているかどうかを
検査する演算子。見つかった場合は、Trule/Falseを返す。


インデクシング

Cで言うところの配列のようなもの。

>>> s = "abcdefg"
>>> s[0]
'a'
>>> s[1]
'b'
>>> s[2]
'c'
>>> s[3]
'd'
>>> s[4]
'e'
>>> s[5]
'f'
>>> s[6]
'g'
>>> s[7]
Traceback (most recent call last):
File "", line 1, in ?
IndexError: string index out of range
>>>



な感じ。存在しない場合は上記のようにエラーになる。
気をつけなきゃいけないのは、Cと違って各要素に値を代入できないこと。

だから、代入しようとすると・・・

>>> s[0] = 'z'
Traceback (most recent call last):
File "", line 1, in ?
TypeError: object does not support item assignment
>>>



と怒られる。
もし、0番目の値を変えたいとするならば、スライシングを使ったりして文字列を再構築する。

あと、添え字に負の数が指定できる。

>>> s = "abcdefg"
>>> s[-1]
'g'
>>> s[-2]
'f'
>>> s[-3]
'e'
>>> s[-4]
'd'
>>> s[-5]
'c'
>>> s[-6]
'b'
>>> s[-7]
'a'
>>>



負の数を指定すると、文字列の最後から添え字が数えられる。
s[-1]と指定した場合はsの最後から一番目の文字、
ということになる。


スライシング

:(コロン)をして抽出文字列の開始位置と終了位置を指定できる。

Syntax
変数名[開始位置:終了位置]


となる。
で、その例。


>>> s = "abcdefg"
>>> s[3:5]
'de'
>>>



「文字列"abcdefg"の最初から3番目の文字から4番目の文字までを抽出せよ」
という意味になる。
終了位置は「含まれない」ので注意が必要。

また、

>>> s = "abcdefg"
>>> s[3:]
'defg'
>>> s[:3]
'abc'
>>>


のように、開始位置、終了位置は省略できる。省略した場合は「残り全部」という意味。
両方とも省略することができる。その場合には文字列「全部」という意味になる。


>>> s = "abcdefg"
>>> s[:]
'abcdefg'
>>>


はたして、両方とも省略するパターンは使用することがあるのかはわからない。。。

スライシングはさらに3つめの添え字も指定できる。
そのときのsyntaxは、

変数名[開始位置:終了位置:いくつおきか]

といった感じ。

3つめの添え字は「シーケンス中の項目をいくつおきに抽出するか」を指定するもの。
といわれてもよくわからないので、実際にやってみよう。

>>> s = "abcdefghijklmnopqrstuvwxyz"
>>> s[0:26:1]
'abcdefghijklmnopqrstuvwxyz'
>>> s[0:26:2]
'acegikmoqsuwy'
>>> s[0:26:3]
'adgjmpsvy'
>>> s[0:26:4]
'aeimquy'
>>> s[0:26:5]
'afkpuz'
>>> s[0:26:6]
'agmsy'
>>> s[0:26:7]
'ahov'
>>> s[0:26:8]
'aiqy'
>>> s[0:26:9]
'ajs'
>>> s[0:26:10]
'aku'
>>> s[0:26:11]
'alw'
>>> s[0:26:12]
'amy'
>>> s[0:26:13]
'an'
>>> s[0:26:14]
'ao'
>>>


なるほど。だいたいわかった。



文字列←→数値変換

int演算子やstr演算子を使うらしい。


>>> a = "123"
>>> int(a) + 1
124
>>> a + str(1)
'1231'
>>>



な感じ。


さて、次は文字列の変更をやってみる。

文字列の変更

たとえば、"abcdefg"という文字列があったとしよう。
この文字列を"aaadefg"という文字列に変更したいとする。

C言語でやった場合は、

char tmp[] = "abcdefg";
tmp[1] = 'a';
tmp[2] = 'a';


とすればよかったものの、Pythonではそうではない。なぜならばPythonでは文字列はimmutableオブジェクトだからである。
では、Pythonで同様のことをするにはどうするか。

まずは同様に操作してみよう。

$ python
Python 2.4.4 (#2, Apr 5 2007, 20:11:18)
[GCC 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> s = "abcdefg"
>>> s[1] = "a"
Traceback (most recent call last):
File "", line 1, in ?
TypeError: object does not support item assignment
>>>

ごらんのとおり、エラーとなってしまう。

正しくは以下のように行う。

$ python
Python 2.4.4 (#2, Apr 5 2007, 20:11:18)
[GCC 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> s = "abcdefg"
>>> s = "aaa" + s[3:]
>>> s
'aaadefg'
>>>

つまり変数sの要素の値を変えるのではなく、変数sを新たに生成する方法をとらなければ
ならない。


さて、次は便利な文字列フォーマットを見ていこう。
文字列フォーマット
Pythonにおける文字列フォーマットは、Cで言うところのsprintfにた役割を果たす。
まずはSyntax。

フォーマット % フォーマットに埋めるオブジェクト(2要素以上であればタプルを使用)


余りを算出する%演算子を使用する。
文字列に対して用いられるとオーバーロードされた演算子%が使用され、
フォーマットとして働く。

では実際の例を見ていこう。

>>> "1 + 1 = %d" % 2
'1 + 1 = 2'
>>>

文字列の中に%dという文字列が存在するが、この値が%演算子以降に書かれている2という
値に置き換わっている。

次は複数要素指定した場合。

>>> "hello, %s 1 + 2 = %d" % ("world", 3)
'hello, world 1 + 2 = 3'
>>>


フォーマットの中に%sと%dの二つが使用されている。
この場合%演算子の後ろにはタプルを用いて指定する。
タプルがいきなり出てきて意味不明だが、とりあえずlistのようなものと思っておく。

以下に文字列フォーマットに使用するコード(%dのようなもの)に何を使用できるか
を一覧にしておく。
コード対応する型
%s文字列
%r文字列(row文字列版)
%c文字
%d10進数
%i整数
%u符号なし整数
%o8進整数
%x16進整数
%X16進整数(A~Fが大文字で出力される)
%e浮動小数点数(指数表記)
%E浮動小数点数(指数表記、eが大文字で出力される)
%f浮動小数点数(10進表記)
%g浮動小数点数(e、f両方の機能を持つ)
%G浮動小数点数(E,f両方の機能を持つ)
%%%文字


さらに細かく指定できる。そのときのSyntaxは以下のとおり。

%[(キー)][フラグ][桁数][.精度]コード


いきなりキーと言われてもいまいちピンとこないと思うので実際の例を以下に。

>>> aval = "abc"
>>> bval = "def"
>>> cval = "ghi"
>>> "%(cval)s %(bval)s %(aval)s" % vars()
'ghi def abc'
>>>


キーというのは、上記で言う()で囲まれた値。cvalとかbvalとか。
これを理解するためにはvars()関数を理解しなければいけない。
vars()関数は、そのコールされた時点で定義されている変数を
ディクショナリにして返してくれる。

だから、

>>> a = "10"
>>> b = "20"
>>> c = "30"
>>> vars()
{'a': '10', 'c': '30', 'b': '20', '__builtins__': , '__name__': '__main__', '__doc__': None}
>>>

のようになる。
a、b、cのほかに__builtins__とかあるが、ここでは無視しておく。
で、上記のキーというのはディクショナリのキーのこと。
だから先ほどの例で、cvalと指定したところにはcvalの値が展開されている。

フラグというのは、+、-、0のことでCと一緒。
+は右よせ、-は左よせ。0は0埋めせよということ。
桁数と精度もCと一緒っぽい。


最後に文字列のメソッドを見ていく。


文字列メソッド


文字列はそれ自身オブジェクトであるので、そのメソッドをコールできる。

文字列のメソッドはたくさんあるので、とりあえずいくつか代表的なものだけ見ていく。

まず下を見てもらいたい。

>>> s = 'xxxxSPAMxxxxSMAPxxxx'
>>> where = s.find('SPAM')
>>> where
4
>>>


s変数は文字列オブジェクトである。sオブジェクトのfindメソッドを呼んでみた例である。
文字列の中にSPAMという文字列がある位置を返している。上記の例では4と返されている。
これはSPAMという文字列の開始インデックスをあらわしている。

上記の値を使用して置換をすると以下のようになる。

>>> s = s[:where] + 'EGGS' + s[(where + 4):]
>>> s
'xxxxEGGSxxxxSMAPxxxx'



もっと簡単に行うにはreplaceメソッドを使えばよい。


>>> s = 'xxxxSPAMxxxxSPAMxxxx'
>>> s.replace('SPAM','EGGS')
'xxxxEGGSxxxxEGGSxxxx'
>>>

簡単に言うと、s/SPAM/EGGS/gという感じ。
gフラグをつけない置換をしたい場合は、

>>> s = 'xxxxSPAMxxxxSPAMxxxx'
>>> s.replace('SPAM','EGGS',1)
'xxxxEGGSxxxxSPAMxxxx'
>>>

とreplaceメソッドの最後の引数に1を指定する必要がある。

文字列オブジェクトは値を変更できないので別の直接変更できるオブジェクトに変換した方が良い場合がある。

>>> S = 'spammy'
>>> L = list(S)
>>> L
['s', 'p', 'a', 'm', 'm', 'y']

上記は、文字列’spammy'を直接変更できるオブジェクトのlistに変換した例。
listに変換しておけばそれぞれの要素を直接編集できる。


>>> L[3] = 'x'
>>> L[4] = 'x'
>>> L
['s', 'p', 'a', 'x', 'x', 'y']



再度listから文字列に戻すには、文字列オブジェクトのメソッドjoinを使用すれば良い。


>>> S = ''.join(L)
>>> S
'spaxxy'
>>>



CのstrtokやPerlのsplitのように文字列を分解するには、splitメソッドを使用する。

>>> line = 'aaa bbb cccc'
>>> cols = line.split()
>>> cols
['aaa', 'bbb', 'cccc']
>>>


とスペースをデリミタとしてトークンに分解できる。結果はリストで返される。
デリミタを指定するにはsplitメソッドの引数として渡してやれば良い。


>>> line = 'aaa,bbb,cccc'
>>> cols = line.split(',')
>>> cols
['aaa', 'bbb', 'cccc']


まとめ

文字列について学んだ。
学んだこと・注意すべき点は以下のとおり。
  • 文字列はimmutableである。
  • 直接操作したい場合は別の型に変換するか、再生成する。
  • オブジェクトなのでメソッドが使用できる。
  • replaceはデフォルトでは全置換。置換数を指定することもできる。
  • フォーマットはCとほぼ一緒な感じで使用できる。キーだけは特殊。
  • Cには無いraw文字列。パスなどを指定する場合に便利。
  • Unicode文字列というのもあり。
  • シングルクォーテーションとダブルクォーテーションは同義。
  • トリプルクォーテーションはブロック文字列を記述するときに便利。
といった感じ。

次はリストについて見ていこうと思う。




[mod_chxj][携帯] POSTされてきたデータのコード変換(絵文字含む)(1)

やろうと思っていたことは以下。

  1. サーバサイドの文字コードを完全にEUC-JP-WIN、SJIS-WIN、UTF-8に対応する。
  2. クライアントサイドへの送信文字コードを設定ファイルにて指定できるようにする。
  3. POSTされてきたデータのコード変換(絵文字含む)
3つあったのだが、内2つは終わった。残りはPOSTされてきたデータのコード変換に手をつける。
恐らくPOSTされてきたデータのコード変換が進むにあたって、1、2の項目にも修正が入る気がする。

とりあえず以下の手順で進める。
  1. 調査(情報を集める。実機で実際にやってみる。)
  2. 変換ルーチン概念設計
  3. 変換ルーチン作成
  4. 影響範囲部分修正
  5. テスト
SoftBankがいろいろとありそう・・・。




.

[mod_chxj][携帯] HTML変換後の出力結果のメタ絵文字を各キャリア用の絵文字(SJIS/UTF8)に変換するコード追加(5)

SoftBankのサーバサイド側 → 携帯端末
間の絵文字変換完成。

UTF-8、SJIS、EUC-JPで書かれたCHTML文書をそれぞれ、
UTF-8で携帯端末に送る場合と、SJISで送る場合を作成した。

端末へ送出する文字コードがUTF-8の場合、絵文字は&#xXXXX;のようなUNICODEの16進参照文字列に変換します。
端末へ送出する文字コードがSJISの場合、絵文字はウェブコード文字列に変換します。

「晴れ」、「げっそり」、「exclamation」、「雲」はOK。
SoftBank系も全絵文字をテストする。







.

2008年1月25日金曜日

[mod_chxj][携帯] HTML変換後の出力結果のメタ絵文字を各キャリア用の絵文字(SJIS/UTF8)に変換するコード追加(4)

次は、KDDI端末向けの変換をやる。


サーバサイド:
EUC-JP、SJIS、UTF8

クライアントサイド:
SJIS



の絵文字変換はOK。



サーバサイド:
EUC-JP、SJIS、UTF-8

クライアントサイド:
UTF8



の絵文字変換もOK。


ただし、テストした絵文字は、「晴れ」と「げっそり」、「exclamation」、「雲」だけ。
後で全絵文字をテストする。

[mod_chxj][携帯] HTML変換後の出力結果のメタ絵文字を各キャリア用の絵文字(SJIS/UTF8)に変換するコード追加(3)

DoCoMoのSJISへの変換もOK。

SJISの場合は2バイトバイナリコードへと変換します。


と思ったら、UTF8、SJIS、EUC-JPの全てのバイナリコードマッチングがうまく動いていなかった。
imodeのNoの順番と、UTF83バイトコードコード、SJIS2バイトコード、EUC-JP3バイトコードの順番が
違うのが原因。
それぞれの文字コードで昇順になるようなインデックス配列を用意して対処した。

[mod_chxj][携帯] HTML変換後の出力結果のメタ絵文字を各キャリア用の絵文字(SJIS/UTF8)に変換するコード追加(2)

とりあえず、DoCoMoでUTF8の場合のパターンはできた。

絵文字はUNICODEの16進数参照文字列に変換されます。





.

[Python][お勉強] Python入門(5) - ビルトインオブジェクト

プログラム作成にあたって中心的なビルトインオブジェクトを勉強します。

数値

1.数値リテラル

数値リテラルの種類は以下のとおり。

  1. 整数と浮動小数点数
  2. 長整数
  3. 16進数、8進数
  4. 複素数

2.式・演算子
Pythonの演算子は以下のとおり。
演算子説明
lambda無名関数生成
or論理和
and論理積
not論理否定
<、<=、>、>=
==、<>、!=、
is、is not、in、not in
比較演算子
|ビット論理和
^ビット排他的論理和
&ビット論理積
<<、>>シフト演算子
-、+加減算
*、%、/、//乗算/繰り返し、剰余/文字列フォーマット、除算
-x、+x、~x、x ** y符号反転、ビット反転、べき乗※xは変数。
x[i]、x[i:j]、x.attr、x(...)インデクシング、スライシング、属性参照、関数呼び出し
(...)、[...]、{...}、`...`タプル、リスト、ディクショナリ、文字列への変換

上の行の方が優先度は低く、下の行の方が優先度が高い。
優先度を明確にするためには括弧を使う。

3.変数
Pythonでは事前の型宣言を必要としない。以下特徴を記す。
  • はじめに値が代入された時点で「入れ物」が作成される。
  • 変数を使用して式を書くと変数に代入された値が使用される。
  • 値が代入されていない変数は使用することができない。
  • 変数の名前だけ宣言することはできない。
例:

$ python
Python 2.4.4 (#2, Apr 5 2007, 20:11:18)
[GCC 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> a = 3 # 変数の作成
>>> b = 4 # 変数の作成
>>> a + 1, a-1 # 加減算
(4, 2)
>>> b * 3, b / 2 #乗除
(12, 2)
>>> a % 2, b ** 2 # 余り、べき乗
(1, 16)
>>> 2 + 4.0, 2.0 ** b # 型の混在
(6.0, 16.0)
>>> c * 2 # 代入していない変数の使用
Traceback (most recent call last):
File "", line 1, in ?
NameError: name 'c' is not defined
>>> b / 2 + a # カッコを使用しないで演算。演算子の優先順が使用される。
5
>>> print b / (2.0 + a) # カッコを使用した演算。カッコが先に評価される。
0.8




また、変数はリファレンスを保持している。よって以下のような場合、

$ python
Python 2.4.4 (#2, Apr 5 2007, 20:11:18)
[GCC 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> a = 3
>>> b = a
>>> a
3
>>> b
3



変数aと変数bは同じ領域をさしている。ただし、bの値を変えてもaの値は変更されない(リストやディクショナリは変更されることもある)。
また、上記の"3"という値は"3"というオブジェクトであるが値を変更できないオブジェクトである。
そのような値を変更できないオブジェクトの特性を不変性(immutability)という。
(変更できるオブジェクトの特性を可変(mutable)という。)


4.数値の表現
以下の例を見てみる。

$ python
Python 2.4.4 (#2, Apr 5 2007, 20:11:18)
[GCC 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> a = 3
>>> b = 4
>>> b / (2.0 + a)
0.80000000000000004
>>> print b / (2.0 + a)
0.8



上記のようにprintステートメントが無い場合とある場合で値が異なっているのがわかる。
これは、printステートメントがある方は浮動小数点数を丸めてくれるからである。


5.ガーベージコレクション
Pythonではメモリアロケーションを意識しなくて良い。ガーベージコレクションによってメモリ領域は自動で開放される。






[mod_chxj][携帯] HTML変換後の出力結果のメタ絵文字を各キャリア用の絵文字(SJIS/UTF8)に変換するコード追加(1)

HTML変換後の文字列の変換までは終わったので、次はメタ絵文字になっている絵文字を適切な文字コードの絵文字に変換するところを追加する。

今考えているのは以下のとおり。

  1. 端末の文字コード(device_data.xml中のcharset項目で指定した値が"SJIS"の場合は、メタ絵文字をSJIS(CP932)のバイナリコードに置換する。
  2. 端末の文字コード(device_data.xml中のcharset項目で指定した値が"UTF8"の場合は、メタ絵文字をユニコード参照文字列に変換する。
2の"UTF8"の場合というのは主にSoftBankの3G携帯をターゲットにしている。
参照文字列に変換する理由は以下のとおり。
  • httpsで直リンクで接続する場合等、バイナリコードだと文字化けを起こす場合がある。
  • POSTされてきた場合、UTF-8にしておいた方が都合が良さそうだから。
曖昧な理由であるが、そんな感じ。

[携帯] ConnectMail - @mac.comも携帯で

メールアドレスの入力チェックなんかは意味不明になる方向。


うざ。

2008年1月24日木曜日

[mod_chxj][携帯] HTML変換後の出力結果をダミーで追加したdevice_dataの出力文字コードにあわせて文字コード変換するコード追加(1)

当面はダミーのパラメータを元にしようかと思ったが、ついでなんでかえてしまおう。
device_data.xmlに、charset項目を追加する。

で、追加後は以下な感じ。


<device>
<device_id>HI21</device_id>
<device_name>C3001H</device_name>
<html_spec_type>XHTML_MOBILE_1_0</html_spec_type>
<width>120</width>
<heigh>130</heigh>
<gif>true</gif>
<jpeg>true</jpeg>
<png>true</png>
<bmp2>false</bmp2>
<bmp4>false</bmp4>
<color>4096</color>
<emoji_type>C</emoji_type>
<wp_width>120</wp_width>
<wp_heigh>116</wp_heigh>
<cache>9740</cache>
<dpi_width>72</dpi_width>
<dpi_heigh>72</dpi_heigh>
<charset>SJIS</charset> ← ここ追加した。
</device>



今のところ、charset項目に指定できる値は、SJISかUTF8のみ。
実際に指定できそうな値は以下のとおり。
  1. CP932
  2. SHIFT-JIS
  3. SHIFT_JIS
  4. SJIS-OPEN
  5. SJIS-WIN
  6. SJIS
  7. MS932
  8. MS_KANJI
  9. UTF8
  10. UTF-8
だが、実際には
  1. UTF8
  2. UTF-8
  3. SJIS
  4. SHIFT_JIS
  5. SHIFT-JIS
ぐらいにしておこうかと思う。

SJIS/SHIFT_JIS/SHIFT-JISを指定された場合は内部的にはCP932に変換し、
端末へ送りつける。


で、上記は完成。あとは端末送出時に適切な絵文字を入れるだけ。

[mod_chxj][携帯] 絵文字定義の再構成(2)

間違えた
絵文字定義の再構成(1)で作った定義ファイルを眺めていたら気づいてしまった。
UTF-8じゃなくてUNICODEじゃないかと。


&#xe63e


上記はDoCoMoのUNICODE絵文字の「晴れ」。
UTF-8であらわすと、

0xee98be


が正解。

ということで定義ファイルと読込ルーチンを再度修正。。。
UTF-8はSJISから変換できるけどcp932が使えないlibiconvの場合困りそうなので、
定義ファイルに追加しておこう。


・・・で、追加完了。
UTF8部も完了。

これで、サーバサイドではEUCJP-WIN/SJIS/UTF-8で記述することが可能になった。
UTF-8の場合だけ注意が必要で、UNICODEのバイナリコードは使用できない。
以下に今回の変更で使用できる絵文字記述方法を書いておく。
  1. UTF-8の10進参照文字列
  2. UTF-8の16進参照文字列
  3. UTF-8のバイナリコード
  4. UNICODEの10進参照文字列(DoCoMoの仕様どおり)
  5. UNICODEの16進参照文字列(DoCoMoの仕様どおり)
  6. EUCJP-WINの10進参照文字列
  7. EUCJP-WINの16進参照文字列
  8. EUCJP-WINのバイナリコード
  9. SJISの10進参照文字列(DoCoMoの仕様どおり)
  10. SJISの16進参照文字列(DoCoMoの仕様どおり)
  11. SJISのバイナリコード(DoCoMoの仕様どおり)

WindowsからDebian-Etchにputty等で接続すれば、特に意識せず上記すべてを
入力できる。バイナリコードは、DoCoMoの提供するi絵文字なるソフトを使用すればOK。
文字コードの変換は端末とvimまかせでOKになるし、実際なった。

[mod_chxj][携帯] 内部コード(SJIS)にHTMLを変換する前に絵文字をメタ絵文字に変換するコード追加(2)

SJISコードの場合はできた。
次は、EUCJPの場合をやる。

バイナリコードは、Debian Etchの/usr/bin/iconvによる変換結果を使用する。

・・・できた。
これでEUCJPの場合の絵文字(iconv依存)もバイナリコードでも、参照文字列でも指定可能。
以下その例。

SJISの場合の太陽は、


&#xf89f;



と指定すれば良いのだが、
EUCJPの場合の太陽は、

&#x8ffca1;


と指定する。文字コード0x8ffca1で直接指定しても可。
そうしておけばあとはmod_chxjが勝手に変換してくれる。


OKそうなので、次はUTF8をやっつける。

2008年1月23日水曜日

[携帯] ディズニー・モバイル


「DM001SH」、「 @disney.ne.jp 」ドメインのメールアドレス



なのだそうだ。

[mod_chxj][携帯] 内部コード(SJIS)にHTMLを変換する前に絵文字をメタ絵文字に変換するコード追加(1)

とりあえず、SJISの場合で且つ参照文字列の場合の処理はできた。


&#xf89f => &chxjEmoji1;
&#63647 => &chxjEmoji1;

絵文字を探すのにバイナリサーチを使用しているが、
バイナリサーチのためのインデックス配列を

static emoji_t *emoji_index[EMOJI_COUNT];

のように内部変数にもってしまったので、
これだとディレクトリ毎の設定ができない。

よって、mod_chxj_configの方へ移すことにしようと思う。

そして、できた。

[Python][お勉強] Python入門(4) データの基礎

Pythonは、データ全てをオブジェクトという概念でもって扱うとのこと。
オブジェクトには、

  • 数値
  • 文字列
  • リスト
  • ディクショナリ(連想配列のようなもの)
  • タプル
  • ファイル
等がある。
またクラスや拡張型という形でユーザ定義オブジェクトを作成することもできる。
もともとPythonに用意されているオブジェクトを「ビルトインオブジェクト」と言ったりする。

初心者のうちは、ビルトインオブジェクトを中心にプログラムを作れば良いらしい。

数値
サポートされている数値型は以下のとおり。
  • 短整数
  • 長整数(無限精度)
  • 浮動小数点数
  • 複素数
長整数はメモリの許す限り必要に応じて桁数を増やす。
8進数、16進数の数値リテラルはC同様に表記できる。

0x9ff # 16進数
0177 # 8進数



複素数は「実数部+虚数部」の形で表す。
虚数部の最後には、「j」または「J」をつける。

3+2j
3+5J



あっそう。
で、

3.2+1

のように複数の型が混在している場合は、
最も複雑な型にそろえられて計算されるとのこと。

[Python][お勉強] Python入門(3) コメントを書くには

コメントは

#


で書きます。#から行がかわるまでがコメントになります。

# こんにちは
print "Hello, World"


な感じに。

ただし、先頭行は、おなじみshebangでっす。
#!/usr/bin/env python
print "ABC123"


な感じでっす。

2008年1月22日火曜日

[mod_chxj][携帯] 変換ルーチンの修正

次は変換ルーチンの修正をします。
やることは、

  1. ダミーでdevice_dataに出力文字コードを記録する場所を追加。今はSJIS固定値。【済】
  2. 絵文字を各キャリア対応の絵文字に変換するルーチンの削除。【済】
  3. 内部コード(SJIS)にHTMLを変換する前に絵文字をメタ絵文字に変換するコード追加。【済】
  4. HTML変換後の出力結果をダミーで追加したdevice_dataの出力文字コードにあわせて文字コード変換するコード追加。【済】
  5. HTML変換後の出力結果のメタ絵文字を各キャリア用の絵文字(SJIS/UTF8)に変換するコード追加。【済】
といった感じでしょうか。

[mod_chxj][携帯] 読込ロジックの修正

絵文字定義ファイルができたので、次は定義ファイルを読み込むところを修正しまっす。

直すべきソースは、

  1. chxj_load_emoji_data.c
だけ。

ちゃっちゃと直しまーす。

できた。

あとはテスト。
モジュールに読み込んだデータをダンプして、etc/emoji.xmlと比較する。

・・・うむ。
よさそうだ。

[Python][お勉強] Python入門(2)トップレベルからスクリプトを実行するには

script.pyというファイル名のスクリプトを実行するには、

$ python script.py


トップレベルからscript.pyを実行するには、

$ python
Python 2.4.4 (#2, Apr 5 2007, 20:11:18)
[GCC 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import script
Hello, World
>>>


とimportを使用します。もう一度importステートメントを発行しても実行されません。
もう一度実行するには、reload()関数を使用します。

python
Python 2.4.4 (#2, Apr 5 2007, 20:11:18)
[GCC 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import script
Hello, World
>>> reload(script)
Hello, World

>>>


へー。

2008年1月21日月曜日

[Python][お勉強] Python入門(1) Pythonのトップレベルを起動するには

O'reillyの「初めてのPython」を読んで勉強する。
学んだことを出力するひとつの手段としてもりもりテキトーに書いていきます。



インタラクティブモードの起動方法は、

$ python


終了するには、
CTRL-D


スクリプトファイルの拡張子は
.py


ふーん。

[mod_chxj][携帯] 絵文字定義の再構成(1)

現状の定義ファイルは以下のとおり。


<set>
<no>4</no>
<imode>
<sjis-hex1>f8</sjis-hex1>
<hex2>a2</hex2<
<string>[絵文字のSJIS2バイトコード</string>
<description>雪 青</description>
</imode>
<ezweb>
<a>60</a>
<b>60</b>
<c>60</c>
<d>60</d>
</ezweb>
<jphone>
<string>$Gh</string>
</jphone>
</set>


これを絵文字定義構造体の再設計(1)で定義した構造にあわせると・・・、


<set>
<no>1</no>
<imode>
<sjis-hex>f89f</sjis-hex>
<sjis-dec>63647</sjis-dec>
<eucjp-hex>8ffca1</eucjp-hex>
<eucjp-dec>9436321</eucjp-dec>
<utf8-hex>e63e</utf8-hex>
<utf8-dec>58942</utf8-dec>
<description>晴れ 赤</description>
</imode>
<ezweb>
<A>
<no>44</no>
<sjis-hex>f660</sjis-hex>
<sjis-dec>63072</sjis-dec>
<utf8-hex>e488</utf8-hex>
<utf8-dec>58504</utf8-dec>
</A>
<B>
<no>44</no>
<sjis-hex>f660</sjis-hex>
<sjis-dec>63072</sjis-dec>
<utf8-hex>e488</utf8-hex>
<utf8-dec>58504</utf8-dec>
</B>
<C>
<no>44</no>
<sjis-hex>f660</sjis-hex>
<sjis-dec>63072</sjis-dec>
<utf8-hex>e488</utf8-hex>
<utf8-dec>58504</utf8-dec>
</C>
<D>
<no>44</no>
<sjis-hex>f660</sjis-hex>
<sjis-dec>63072</sjis-dec>
<utf8-hex>e488</utf8-hex>
<utf8-dec>58504</utf8-dec>
</D>
</ezweb>
<softbank>
<no>74</no>
<sjis-hex>1b24476a0f</sjis-hex>
<sjis-dec>2147483647</sjis-dec>
<utf8-hex>e04a</utf8-hex>
<utf8-dec>57418</utf8-dec>
</softbank>
</set>
といった感じ。あとは定義ファイルを上記にのっとって修正するだけ。

Schemeでごにょごにょ。。。

で、ごにょごにょするSchemeのソースはこんな感じ・・・。
#!/usr/bin/env gosh

(use text.csv)
(use srfi-1)

(define-macro (define-accessors name-lst)
`(begin
,@(map (lambda (nm n)
`(define ,nm
(lambda (lst)
(list-ref lst ,n))))
name-lst
(iota (length name-lst)))))

(define-accessors
(docomo-no
docomo-name
docomo-sjis-hex
docomo-sjis-dec
docomo-eucjp-win-hex
docomo-eucjp-win-dec
docomo-utf8-hex
docomo-utf8-dec
au-no
au-sjis-hex
au-sjis-dec
au-utf8-hex
au-utf8-dec
softbank-no
softbank-sjis-hex
softbank-sjis-dec
softbank-utf8-hex
softbank-utf8-dec))

(define csv->xml
(lambda (reader)
(call-with-input-file "list.csv"
(lambda (in)
(port-for-each (lambda (lst)
(display #`"<set>
<no>,(docomo-no lst)</no>
<imode>
<sjis-hex>,(docomo-sjis-hex lst)</sjis-hex>
<sjis-dec>,(docomo-sjis-dec lst)</sjis-dec>
<eucjp-hex>,(docomo-eucjp-win-hex lst)</eucjp-hex>
<eucjp-dec>,(docomo-eucjp-win-dec lst)</eucjp-dec>
<utf8-hex>,(docomo-utf8-hex lst)</utf8-hex>
<utf8-dec>,(docomo-utf8-dec lst)</utf8-dec>
<description>,(docomo-name lst)</description>
</imode>
<ezweb>
<A>
<no>,(au-no lst)</no>
<sjis-hex>,(au-sjis-hex lst)</sjis-hex>
<sjis-dec>,(au-sjis-dec lst)</sjis-dec>
<utf8-hex>,(au-utf8-hex lst)</utf8-hex>
<utf8-dec>,(au-utf8-dec lst)</utf8-dec>
</A>
<B>
<no>,(au-no lst)</no>
<sjis-hex>,(au-sjis-hex lst)</sjis-hex>
<sjis-dec>,(au-sjis-dec lst)</sjis-dec>
<utf8-hex>,(au-utf8-hex lst)</utf8-hex>
<utf8-dec>,(au-utf8-dec lst)</utf8-dec>
</B>
<C>
<no>,(au-no lst)</no>
<sjis-hex>,(au-sjis-hex lst)</sjis-hex>
<sjis-dec>,(au-sjis-dec lst)</sjis-dec>
<utf8-hex>,(au-utf8-hex lst)</utf8-hex>
<utf8-dec>,(au-utf8-dec lst)</utf8-dec>
</C>
<D>
<no>,(au-no lst)</no>
<sjis-hex>,(au-sjis-hex lst)</sjis-hex>
<sjis-dec>,(au-sjis-dec lst)</sjis-dec>
<utf8-hex>,(au-utf8-hex lst)</utf8-hex>
<utf8-dec>,(au-utf8-dec lst)</utf8-dec>
</D>
</ezweb>
<softbank>
<no>,(softbank-no lst)</no>
<sjis-hex>,(softbank-sjis-hex lst)</sjis-hex>
<sjis-dec>,(softbank-sjis-dec lst)</sjis-dec>
<utf8-hex>,(softbank-utf8-hex lst)</utf8-hex>
<utf8-dec>,(softbank-utf8-dec lst)</utf8-dec>
</softbank>
</set>
"))
(lambda () (reader in)))))))

(csv->xml (make-csv-reader #\tab))


・・・できた。
きっともっとかっこよくできるに違いない。

[mod_chxj][携帯] 絵文字定義構造体の再設計(1)

現状は以下な感じ。


typedef struct imode_emoji_t imode_emoji_t;

struct imode_emoji_t {
char hex1byte;
char hex2byte;
char *string;
char *description;
};

typedef struct ezweb_emoji_t ezweb_emoji_t;

struct ezweb_emoji_t {
char *typeA;
char *typeB;
char *typeC;
char *typeD;
};

typedef struct jphone_emoji_t jphone_emoji_t;

struct jphone_emoji_t {
char *string;
};

typedef struct emoji_t emoji_t;

struct emoji_t {
struct emoji_t *next;
int no;
imode_emoji_t *imode;
ezweb_emoji_t *ezweb;
jphone_emoji_t *jphone;
};



で、imode_tはSJIS、EUC-JP、UTF-8に対応したいので、それぞれの文字コードを記憶しておくために、SJIS用データ、EUC-JP用データ、UTF-8用データ記憶領域を追加。
typedef struct imode_emoji_t {
char *sjis_hex_string;
char *sjis_dec_string;
char sjis_hex[2];

char *euc_hex_string;
char *euc_dec_string;
char euc_hex[3];

char *utf8_hex_string;
char *utf8_dec_string;
char utf8_hex[2];

char *description;
} imode_emoji_t;
後に比較しやすいように文字列でも持っておく。

EzWeb用は、SJISとUTF-8用記憶領域があればよいので、

typedef struct ezweb_type_t {
char *sjis_hex_string;
char *sjis_dec_string;
char sjis_hex[2];

char *utf8_hex_string;
char *utf8_dec_string;
char utf8_hex[2];
} ezweb_type_t;

typedef struct ezweb_emoji_t {
ezweb_type_t typeA;
ezweb_type_t typeB;
ezweb_type_t typeC;
ezweb_type_t typeD;
} ezweb_emoji_t;



といった感じかな。
SoftBankも同様にSJISとUTF8を保持するので、

typedef struct softbank_emoji_t {
char *sjis_hex_string;
char *sjis_dec_string;
char sjis_hex[6];

char *utf8_hex_string;
char *utf8_dec_string;
char utf8_hex[2];
} softbank_emoji_t;


といった感じ。この機会にjphoneはsoftbankに変えとこう。
で、何か似た感じなので共通化して、念のためにそれぞれの絵文字番号も入れて最終的には以下の感じ。


typedef struct emoji_data_t {
char *hex_string;
char *dec_string;
char hex[6];
} emoji_data_t;

typedef struct imode_emoji_t {
emoji_data_t sjis;
emoji_data_t euc;
emoji_data_t utf8;
char *description;
} imode_emoji_t;

typedef struct ezweb_type_t {
int no;
emoji_data_t sjis;
emoji_data_t utf8;
} ezweb_type_t;

typedef struct ezweb_emoji_t {
ezweb_type_t typeA;
ezweb_type_t typeB;
ezweb_type_t typeC;
ezweb_type_t typeD;
} ezweb_emoji_t;

typedef struct softbank_emoji_t {
int no;
emoji_data_t sjis;
emoji_data_t utf8;
} softbank_emoji_t;

typedef struct emoji_t {
struct emoji_t *next;
int no;
imode_emoji_t imode;
ezweb_emoji_t ezweb;
softbank_emoji_t softbank;
} emoji_t;


で完成。

2008年1月20日日曜日

[mod_chxj][携帯] サーバサイド絵文字変換の概念設計

やろうと思っていることは以下のとおり。

  • SJIS、EUCJP、UTF-8で書かれているCHTML/HTML文書を絵文字も含めてSJISに変換すること。
さて、やはり問題になるのは「絵文字」。下記に各々の文字コードの時にやらなきゃいけなさそうなことを列挙してみます。とりあえずはクライアントに渡す文字コードはSJISコード前提とします。libiconvを使うので環境によってはSJIS-WINや、EUCJP-WINが使えないので絵文字の変換は自力でやらなきゃならなそう。内部的には絵文字は文字コードに依存しないメタ絵文字を使用し、最終出力時にSJISに変換した方がいいかな。


サーバサイドのソースがSJISコードのとき
絵文字は2バイトの指定文字、もしくは参照文字列で指定します。
アクセスしてきた端末がDoCoMoの場合にやるべきことは、
  1. 2バイトバイナリコードの絵文字をメタ絵文字に変換。
  2. 参照文字列をメタ絵文字に変換。
  3. HTML変換。
  4. メタ絵文字を2バイトバイナリコード絵文字に変換。
だけ。
auの場合は、
  1. 2バイトのバイナリコードで記述された絵文字をメタ絵文字へ変換
  2. 参照文字列で記述された絵文字をメタ絵文字へ変換
  3. HTML変換
  4. メタ絵文字をAU用絵文字に変換。
SoftBankの場合は、
  1. 2バイトのバイナリコードで記述された絵文字をメタ絵文字へ変換
  2. 参照文字列で記述された絵文字をメタ絵文字へ変換
  3. HTML変換
  4. メタ絵文字をSoftBank用絵文字に変換
といったところか。



サーバサイドのソースがEUC-JPの場合
絵文字はEUC-JPの参照文字列で指定します。

端末がDoCoMoの場合、
  1. 参照文字列で記述された絵文字をメタ絵文字に変換
  2. ソースをSJISに変換(iconv使用)
  3. HTML変換
  4. メタ絵文字をDoCoMo用絵文字に変換
端末がAUの場合、
  1. 参照文字列で記述された絵文字をメタ絵文字に変換
  2. ソースをSJISに変換(iconv使用)
  3. HTML変換
  4. メタ絵文字をAU用絵文字に変換
端末がSoftBankの場合
  1. 参照文字列で記述された絵文字をメタ絵文字に変換
  2. ソースをSJISに変換(iconv使用)
  3. HTML変換
  4. メタ絵文字をSoftBank用絵文字に変換


サーバサイドのソースがUTF-8の場合
絵文字は2バイトバイナリコードか、参照文字列で指定します。

端末がDoCoMoの場合、
  1. 2バイトバイナリコードで記述された絵文字をメタ絵文字に変換
  2. 参照文字列で記述された絵文字をメタ絵文字に変換
  3. ソースをSJISに変換(iconv使用)
  4. HTML変換
  5. メタ絵文字をDoCoMo用絵文字に変換
端末がAUの場合、
  1. 2バイトバイナリコードで記述された絵文字をメタ絵文字に変換
  2. 参照文字列で記述された絵文字をメタ絵文字に変換
  3. ソースをSJISに変換(iconv使用)
  4. HTML変換
  5. メタ絵文字をAU用絵文字に変換
端末がSoftBankの場合
  1. 2バイトバイナリコードで記述された絵文字をメタ絵文字に変換
  2. 参照文字列で記述された絵文字をメタ絵文字に変換
  3. ソースをSJISに変換(iconv使用)
  4. HTML変換
  5. メタ絵文字をSoftBank用絵文字に変換

な感じかな。


メタ絵文字
&__chxj_EmojiDoCoMo絵文字番号

でいいや。

結局、

&chxjEmojiDoCoMo絵文字番号


な感じ。

[mod_chxj][携帯] サーバサイドの文字コードを完全にEUC-JP-WIN、SJIS-WIN、UTF-8に対応する(2)

サーバサイド側用のiモードから他キャリアへの変換はこんな感じ。

http://spreadsheets.google.com/pub?key=p5XOtho4dsT_KzqSM7tclIg

EUCJPはiconvの変換結果。可逆だけど怪しい。まぁいいか。


あとは、

EzWEB->iモード



SoftBank->iモード

の変換テーブルは、POSTデータを変換するときにのみ必要なので、
とりあえず置いといて、組み込んでみることにする。


やることは、
  1. サーバサイド絵文字変換の概念設計【済】
  2. 絵文字定義構造体の再設計【済】
  3. 絵文字定義の再構成【済】
  4. 読込ロジックの修正【済】
  5. 変換ルーチンの修正【済】
  6. テスト
を予定。