Python レシピの増量、ひと段落
http://lightson.dip.jp/zope/ZWiki/FrontPage/recentchanges 。25 個以上追加して満足。
067:文字列を最大n桁に切り詰める
East Asian Width 使用版。
# coding: utf-8 from unicodedata import east_asian_width _east_asian_width = { 'Na': 1, 'N': 1, 'W': 2, 'H': 1, 'A': 2, } def take_ncols(s, n): length = 0 result = [] for c in s: length += _east_asian_width[east_asian_width(c)] if length > n: break result.append(c) return u''.join(result) def test(): print take_ncols(u'a'* 30, 20) print take_ncols(u'あ'* 30, 20) print take_ncols(u'a'* 15 + u'あ' * 15, 20) if __name__ == '__main__': test()
123:2つのハッシュの両方にあるキー/一方にしかないキーを見つける
集合型の出番。
>>> dict1 = {'a': 1, 'b': 2} >>> dict2 = {'a': 3, 'c': 4} >>> set(dict1) & set(dict2) set(['a']) >>> set(dict1) ^ set(dict2) set(['c', 'b'])
065:文字列を最大nバイトに切り詰める
放置してきた一品。とうとう手をつけた。出来はしたものの、このレシピには出番はあるのだろうか? あと速度も心配。
# coding: utf-8 def _shift_jis(c): if c <= '\x7f' or '\xa1' <= c <= '\xdf': return 1 elif '\x81' <= c <= '\x9f' or '\xe0' <= c <= '\xfc': return 2 raise ValueError(repr(c)) def _euc_jp(c): if c <= '\x7f': return 1 elif c == '\x8e' or '\xa1' <= c <= '\xfe': return 2 elif c == '\x8f': return 3 raise ValueError(repr(c)) def _utf_8(c): if c <= '\x7f': return 1 elif '\xc0' <= c <= '\xdf': return 2 elif '\xe0' <= c <= '\xef': return 3 elif '\xf0' <= c <= '\xf7': return 4 elif '\xf8' <= c <= '\xfb': return 5 elif '\xfc' <= c <= '\xfd': return 6 raise ValueError(repr(c)) _code = { 'shift_jis': _shift_jis, 'euc_jp': _euc_jp, 'utf_8': _utf_8, } def take_nbytes1(str_, n, code): u""" 文字列 str_ を最大 n バイトに切り詰める str_: 8 ビット文字列 n: 最大のバイト数。これより長い場合、切り詰める code: str_ の文字コード ['shift_jis', 'euc_jp', 'utf_8'] """ length = 0 buf = [] f_code = _code[code] i = iter(str_) try: while True: c = i.next() width = f_code(c) length += width if length > n: break buf.append(c) for _ in range(width - 1): buf.append(i.next()) except StopIteration: pass return ''.join(buf) def _test(): def _write(f, code): s = u'あいうえおかきくけこさしすせそたちつてと'.encode(code) for i in range(1, 40): f.write(take_nbytes1(s, i, code)) f.write('\n') f_sjis = open('_sjis.txt', 'w') try: _write(f_sjis, 'shift_jis') finally: f_sjis.close() f_euc = open('_euc.txt', 'w') try: _write(f_euc, 'euc_jp') finally: f_euc.close() f_utf8 = open('_utf8.txt', 'w') try: _write(f_utf8, 'utf_8') finally: f_utf8.close() if __name__ == '__main__': _test()
2009/2/9 修正、 Shift JIS のコードに過ちあり。 2 バイト文字先頭の条件のひとつめ、 '\x81' <= c <= '\x9f' が '\x81' <= c <= '\x91' となってしまっていたので修正しました。以下、テストコードです。
import split_065 import unittest class TestCode(unittest.TestCase): def testshift_jis(self): for i in xrange(0xffff): try: c = unichr(i).encode('shift_jis') self.assertEqual(len(c), split_065._shift_jis(c[0])) except UnicodeError: pass def testeuc_jp(self): for i in xrange(0xffff): try: c = unichr(i).encode('euc_jp') self.assertEqual(len(c), split_065._euc_jp(c[0])) except UnicodeError: pass def testutf_8(self): for i in xrange(0xffff): c = unichr(i).encode('utf_8') length = len(c) self.assertEqual(len(c), split_065._utf_8(c[0])) if __name__ == '__main__': unittest.main()