以前に「Python の シーケンス型に慣れる」で書いたが、「文字列」と「シーケンス」の関係を改めて見直してみる。あれから 4 ヶ月近く経過しているので、そのときとはまた違った見方になっているかもしれない。頭の中を整理したい。てゆうか、自分で書いておきながらほとんど忘れてるので再学習を。 ^^;
例
そんなことを考えるキッカケとなった簡単な例題。
IP アドレス、例えば `192.168.0.1’ があったときに、`.’ の前に `\’ を入れたい。
ちなみに、これは「Google Analytics で自分がカウントされないようにする」ための設定で使った。(もちろん、実際には IP アドレスはグローバルな値だけれど。) 設定した値が正規表現と解釈されるので、特定の IP アドレスを指定したい場合は、`.’ をエスケープしなくてはいけない。
文字列のメソッドを使う場合
対象を文字列として見るなら、2.3.6.1 文字列メソッド replace を使って、
ip = "192.168.0.1 " print ip.replace('.','\.')
以下、変数 ip を使用する。
正規表現を使う場合
正規表現 の sub メソッド を使うなら、
import re print re.sub(r'\.', r'\\.', ip)
後方参照を使うなら、
print re.sub(r'(\.)', r'\\\1', ip)
シーケンスとして考える場合
for ループを使って
文字列はシーケンスなので、for ループに投入すると「文字」ごとの処理となる。(cf. 2.3.6 シーケンス型)
result = "" for e in ip: if e == "." : result += "\\" + e else: result += e print result
map, reduce を使って
文字列を「文字のリスト」として見て、map を適用するなら、
print "".join(map(lambda x: "\." if x == "." else x, ip))
文字列を一文字ずつ見て、`.’ なら '`\.’ に変換する。(cf. Python の map, filter, reduce とリスト内包表記)
map で書けるなら reduce でも、
print reduce(lambda a,b: a+b if b != "." else a+"\\"+b, ip, "")
文字列なので、空の文字を先頭要素として結合していく。そのため、最後で join を使わなくて済む。
リスト内包表記を使って
map, reduce を使えるなら、同じことをリスト内包表記を使って、
print "".join(x if x != "." else "\\" + x for x in ip)
これは lambda を使った以下と同じかな。
print "".join((lambda x: x if x != "." else "\\" + x)(x) for x in ip)
再帰で考える
リスト (シーケンス) として見たてるなら、お約束通り再帰を適用して、
def escape(S): if len(S) > 1: return escape(S[0]) + escape(S[1:]) else: return S if not S == "." else "\\" + S print escape(ip)
(cf. Python でリストに対する再帰的な関数の適用)
全く意味はないけれど、以前に見た proc を使った Ruby の書き方 を真似するなら、上記の再帰を条件式を使って書換えれば、
fn = lambda(S): fn(S[0]) + fn(S[1:]) if len(S) > 1 else S if not S == "." else "\\" + S print fn(ip)
(cf. Python の条件式)
Python の lambda 内で使えるのは「式」だけだから、代入はできないので二行に。こんなコードあったら読みたくない… (@_@;) CCC
0コメント:
コメントを投稿