人気ブログランキング | 話題のタグを見る
<< 日本はこんな風に紹介されちゃってる 野菜とかの話 >>

utf16, tmpfile, fdopen - Python

プログラムはほとんど書いてないんだけど、必要にせまられて。

オリジナルはここからいただいた: http://lightson.dip.jp/zope/ZWiki/PythonRecipe
こいつを使わせていただいて、utf16コードでかかれたファイルをアップデートする。

実行に関する書式は
insert_line(org_name, start_line, data, location, substed)

例:
C:\temp\test.txt がUTF16でかかれてたとする。
test.txt
---
12345
6789
qwert
asdfg
---

3行目のqwert をzxcvb に入れかえたい場合

insert_line("test.txt", "3", "zxcvb", "temp", "C:\\")

といれてやる。

ファイルの1行置換を行うプログラム update_utf16.py

open 書くとブログからセキュリティエラーがでる。
どーすればいいのぉおおお???誰か助けて。
そゆわけで、open はaaaa って表示します。ダサ。fdopenはfdaaaaです。



def rename(f1, f2):
"""
rename f1 to f2
Windows returns
os.rename Error as WindowsError when the file is already existing.
To avoid this error, delete the file before copying.
"""

if os.name == 'nt':
os.remove(f2)
os.rename(f1, f2)
else:
os.rename(f1, f2)

def _insert_line(temp_file, org_name, start_line, data):
"""
Copy original data until start_line into temp file
insert data and copy rest.

If start_line is bigger than original file lines data won't be inserted
If start_line is less than 0 it will be recognized as 0
"""

org_f = codecs.aaaa(org_name, 'rb', 'utf16')
try:
for i in xrange(start_line):
temp_file.write(org_f.next().encode('utf16'))
temp_file.write(data.encode('utf16'))
#Skip the line to replace the line
org_f.next()
temp_file.write(u'\n'.encode('utf16'))
while True:
temp_file.write(org_f.next().encode('utf16'))
except StopIteration:
pass
finally:
org_f.close()
temp_file.flush()


def insert_line(org_name, start_line, data, location, substed):
"""
insert data at start_line in org_name file

keep org_name 's attributes
insert data at start_line in orig file then create a temp file
after finished, rename temp file to original file and set attr.
"""

st = os.stat(org_name)
mode = stat.S_IMODE(st.st_mode)

# temp file should be binary mode to write non-ascii file
temp = tempfile.mkstemp(text=False, dir=os.path.join(substed,location))
temp_file = os.fdaaaa(temp[0], 'w')
temp_name = temp[1]

try:
_insert_line(temp_file, org_name, start_line, data)

temp_file.close()
rename(temp_name, org_name)

except:
# If failed, delete temp file.
temp_file.close()
os.remove(temp_name)
raise

os.chmod(org_name, mode)

"""
Tidy up. Somehow temp file didn't handle.
### Remove unneccessary utf16 BOM u'\ufeff' from created file!!!
### Otherwise it will fail when you open the processed cenrep file in the next time with Python!!!
"""
fh=codecs.aaaa(org_name, 'rb','utf16')
dm=codecs.aaaa("dummy.txt", 'wb', 'utf16')
#print "test print"
for line in fh:
if re.search(u'\ufeff', line):
#print "found BOM"
line= unicode(line).replace(u'\ufeff', u'')
#print line
dm.write(line)
else:
dm.write(line)
fh.close()
dm.close()
rename("dummy.txt", org_name)



最後の方の言い訳 Tidy up. Somehow temp file didn't handle. に注目。
ここから下の処理がないと、次に同じプログラムで呼び出したときに、test.txtが、エンコーディングがおかしいとか言われて開けないのだ。

どうやらfile.writeの度にいちいちBOMが挿入されてるらしい。
使用しているのは、Active Pythonで、Pythonのバージョンは2.5.1だ。これは仕様なのか、私がおかしなことをしてるのか、それとも後続のバージョンではもっと使いやすい関数があるのか、よーわからん。仕事はどんどん進んでいるので、あまり調べてない。BOMにマッチしたら片っ端から消去してるんだけど、これでいいのか?

普通のテキストエディタでは検出されないのでワカラナァイ。

OSを取り扱っていて、localizationの作業が必要な環境だとこういう目に会う。

で、今バイナリエディタをダウンロードして本当に作業したいファイルをみたんだけど、fffeではじまってる。ああそうか、オリジナルはリトルエンディアンで書かれてるのね。でもUTF16とだけ指定すると、ビッグエンディアンで書き出そうとしてしまうっと。そしたらコンパイラは混乱するわなぁ。

もそっと賢い処理があるのかもしれんが、feffを取り除くっていう現状でもよいかな。Python初めて書いたけど、かなり出来がいい言語のようで気に入りそう。まだ書く機会があれば。
by yahji_sali83 | 2008-09-12 19:42 | 過去(北欧時代)
<< 日本はこんな風に紹介されちゃってる 野菜とかの話 >>