なにげに前回(▼)の続きです。
- 10進数から2桁の16進数を得たい
http://qiita.com/it_ks/items/55d43baa996860edaabb
シーン内に日本語名がついたオブジェクトがあるとき、
FBXで渡すと下記のようなオブジェクト名に変換されてしまいます。
FBXASC229FBXASC137FBXASC141FBXASC233FBXASC171FBXASC1702
oh! Fxxk!!
マテリアルやテクスチャ、ブレンドターゲットなんかも同様になりますので、
かなりいっぱいこういうのが錬成されます。
なんとかしたい
以下のようにしてみました。
from binascii import a2b_hex as a2b
def fbxasc_to_chr( target_str ):
return_list = []
stock = ''
for var in target_str.split( 'FBXASC' ):
# 空だったら無視する
if not var:
continue
# 1文字目がアルファベットだったら対象外 return_listに足して次へ。
if var[0].isalpha():
return_list.append(var)
continue
# 字数が3より多ければ、3文字目までをint変換
ex_digit = ''
if len(var)>3:
ex_digit = var[3:]
code_int = int(var[:3])
else:
code_int = int(var)
stock +=hex( code_int )
try:
return_list.append( a2b(stock.replace('0x','')).decode('utf8') )
except UnicodeDecodeError:
continue
# decode、appendができたらリセット
stock = ''
if ex_digit:
return_list.append(ex_digit)
return ''.join(return_list)
ふんわり解説
ファッキンFBX文字列をみてみると、**「FBXASC」**というのが定期的に入っていることが観察できます
もっというと
FBXASC + 0-255
の組み合わせです。
これを一つの単位(1バイト)として、いくつか並んだ時に文字としてデコードできます。
いくつかというのは、1つで成立するときもあるし、3つで成立するときもあるということです。
なかなかにややこしいので詳細はUTF-8の解説@wikipediaにお任せしますが
https://ja.wikipedia.org/wiki/UTF-8#.E6.96.87.E5.AD.97.E7.A8.AE
(▲)この表によると、英数記号は1、「東アジアの諸文字・全角」は3、なようです。
第3・第4水準の漢字の一部は4とありますね。
hex
0-255のままでは使えませんので、16進数に直します。
これが冒頭でも言及した、前回の記事です。hex関数を使うことにしました。
変換後には必ず0x
がつきますが、これを、アスキーからバイナリに変換する前にまとめて除去しています。
〜〜.replace('0x','')
アスキー -> バイナリ変換
ここまででは、まだ「 0-9a-f でできた文字列」です。
これをバイナリに変換します。
binasciiモジュールのa2b_hex関数を使います。
- 19.8. binascii — バイナリデータと ASCII データとの間での変換
https://docs.python.jp/3/library/binascii.html#binascii.a2b_hex
ここではimport時に端的に「a2b」としています。
アスキー -> バイナリ変換後は decodeメソッド が使えますが、存在しない番地だとデコードエラーが発生します。
このエラーを拾って、もしデコードエラーが起きるようなら次に持ち越し、連結して再度変換、という流れになっています。
FBXASC化されてない愉快な仲間たちへの対処
文字列全部が「FBXASC+0-255」になってくれていれば話は早いのですが……
例えば「.」は「FBXASC046」に書き換えられて登場するのですが、
普通の英数は英数のまま文字列に混ざってきます。
なので、単純にFBXASCでsplitしただけだと、得られるリストの中に「4桁の数値*(0-255の幅じゃなくなってしまう)」や、「3桁+英文字(hexに渡す前にint変換できない)*」が含まれてしまいます。
はみ出た桁はex_digit という変数に入れてあとから連結することにしました。
またオブジェクト名が英数字で始まる/終わる場合は、FBXASCでsplitされない要素が最初/最後にどれくらいつくかわかりませんので、なんかそれっぽくなるようifで仕分けします('A`)
結果、なんかもっとあるだろという気がしてなりません(笑
あと今気づいたんですが、これだともとから0-255の数字が含まれていた場合逆に化けちゃうのじゃないかという謎の心配がありますー疲れたのでまいいや
まとめ
シーン内に日本語を含めた車輌は全員シベリア送り25ルーブルよ!
参考
- Python3で文字列を処理する際の心掛け
http://qiita.com/FGtatsuro/items/f45c349e06d6df95839b - 16進文字列と文字列の変換
http://qiita.com/atsaki/items/6120cad2e3c448d774bf - [修正] Python 文字列の英数字判定でハマった
http://qiita.com/fujiy/items/f738aa9d0bb7427e07a4