[[diary/Kojima]]

・Unicode

最近,python で遊んでいることもあって,Unicode/UTF-8 へのアレルギーが多
少は改善されてきた感じ.

例えば,以下は最近書いた Windows の cp932 で作ったファイル名を euc-jp
に変換する Python のスクリプトの一部.手元ではローマ数字を使ったファイ
ル名にぶつかることがあるのだけど,ローマ数字は euc-jp の世界には存在し
なくて,nkf のレベルだとうまく変換してくれないので,Unicode な世界で英
数字に変換してから euc-jp にするような感じにしてみた.

 def check_roman(s):
     table = ( (u'\u2160' , u'I'),
               (u'\u2161' , u'II'),
               (u'\u2162' , u'III'),
               (u'\u2163' , u'IV'),
               (u'\u2164' , u'V'),
               (u'\u2165' , u'VI'),
               (u'\u2166' , u'VII'),
               (u'\u2167' , u'VIII'),
               (u'\u2168' , u'IX'),
               (u'\u2169' , u'X'),
               (u'\u216A' , u'XI'),
               (u'\u216B' , u'XII'),
               (u'\u216C' , u'L'),
               (u'\u216D' , u'C'),
               (u'\u216E' , u'D'),
               (u'\u216F' , u'M'),
               (u'\u2170' , u'i'),
               (u'\u2171' , u'ii'),
               (u'\u2172' , u'iii'),
               (u'\u2173' , u'iv'),
               (u'\u2174' , u'v'),
               (u'\u2175' , u'vi'),
               (u'\u2176' , u'vii'),
               (u'\u2177' , u'viii'),
               (u'\u2178' , u'ix'),
               (u'\u2179' , u'x'),
               (u'\u217A' , u'xi'),
               (u'\u217B' , u'xii'),
               (u'\u217C' , u'l'),
               (u'\u217D' , u'c'),
               (u'\u217E' , u'd'),
               (u'\u217F' , u'm'),
               (u'\u2180' , u'1000'),
               (u'\u2181' , u'5000'),
               (u'\u2182' , u'10000'),
               (u'\u2183' , u'r100'),
               (u'\uff5e' , u'〜')
               )
 
     new_str = ''
     for i in s[:]:
         match = False
         for j in table:
             if i.find(j[0]) >= 0:
                 new_str = new_str + j[1]
                 match = True
                 break
         if match == False:
             new_str = new_str + i
     return new_str
 
 files = os.listdir('.')
 for i in files:
     utf_name = i.decode('cp932')
     new_name = check_roman(utf_name)
     os.rename(i, new_name.encode('euc-jp'))

Python の場合,不変なオブジェクトと可変なオブジェクトがあって,文字列は
不変なオブジェクトだから,既存の文字列を置換するのではなく,新しいオブ
ジェクトに一文字ずつチェックしながらコピーするような形にしているのだけ
ど,unicode な文字列だと,バイト列みたいに 1バイト目や 2 バイト目といっ
た条件を気にしなくていいので処理は楽な感じ.

あと,Python の場合は内部 Unicode なので,外部から取ってきた文字列は,
外部の文字コードを指定して Unicode に decode してやり,外部に出す時はそ
れぞれの文字コードに encode してやる,というのもちょっと最初は戸惑った
のだけど,「Python チュートリアル」の付録で鴨澤さんが書いてた

 Pythonの(というか元々の意味での)「Unicode 文字列」とは,「世界中の文字が全
 部入った抽象オブジェクト(文字集合)」である.この大元の抽象オブジェクトから,
 個々のエンコーディング(codec)に「エンコード」してやると,現実世界で表示や書
 き出しが可能な状態になるのだ.一方「デコード」とは,文字の現実世界でのかりそ
 めの表現を,「魂の集積所」である Unicode 空間に解き放ってやることである.

という(「エヴァンゲリオン」を思わせるような :-)表現でよく理解できた.

で,この Unicode 空間を Unix なファイル名とぶつからないように投影したの
が UTF-8 だ,と考えると(euc-jp ほど,日本語を簡潔できれいには表現できな
くても) 悪くはないかなぁ,,という気がしてきた(笑
- ○付き数字にも対応してみた          
  (u'\u2460' , u'(1)'),
  (u'\u2461' , u'(2)'),
  (u'\u2462' , u'(3)'),
  (u'\u2463' , u'(4)'),
  (u'\u2464' , u'(5)'),
  (u'\u2465' , u'(6)'),
  (u'\u2466' , u'(7)'), 
  (u'\u2467' , u'(8)'),
  (u'\u2468' , u'(9)')
[[kojima]] &new{2008-04-01 (火) 22:12:18};
-これまで convmv http://j3e.de/linux/convmv 使っていたのですが、いわゆる機種依存文字をこのように変換掛けてくれる方法もあったのですね。この記事に感謝! -- [[通りすがり]] &new{2008-04-05 (土) 09:33:33};
-table をタプルではなく、ディクショナリで持つようにして、キーだけをリストにしておけば、in で該当するかどうかをチェックできるからループの中でループを回す必要はなくなるね。

  def check_roman(s):
     table = { 
         u'\u2160':u'I',
         u'\u2161':u'II',
         u'\u2162':u'III',
         ....
         u'\u2468':u'(9)'
         }
 
      L=[]
      for i in table.keys():
          L.append(i)
 
     new_str = ''
     for i in s[:]:
         if i in L:
             new_str = new_str + table[i]
         else:
             new_str = new_str + i
     return new_str

たぶん、こっちの方が効率もよさそう -- [[kojima]] &new{2008-04-07 (月) 09:16:35};

#comment

トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS