Pythonの文字コード変換: UTF-16からUTF-8への変換

投稿者: Anonymous

元質問

str型のオブジェクトに、UTF-16がUTF-8として入力されてしまっているため、これをUTF-8に変換したいと考えております。
具体的な例を挙げると、result = "\u3053\u306e\u4eba"という形で与えられていて、ここから余計なを取り除いた上で、「この人」という出力を得たいです(こちらのサイトで変換することで元はUTF-16ということが判明)。

result2 = "u3053u306eu4eba"
result2

とすると、「この人」という結果が得られることから、が余計に入っていることが原因だと考え、re.sub(r"\\", "\", result)を試しましたが、error: bogus escape (end of line)というエラーが発生して正規表現を使うことができません。

使用環境はMac OS 10.9、Python 3.4.3です。よろしくお願いいたします。


追記

早速反応を頂き、ありがとうございます。頂いたコメントを踏まえて追記します。

Takayuki SHIMIZUKAWAさん:
 元の質問にある\u3053\u306e\u4ebaを、こちらのサイトで変換させたところ、UTF-16だけで日本語として読むことのできる結果が返ってきたため、UTF-8ではなくUTF-16だろうと推測しました。
 作りかけの長いプログラムの一部分なので全てを貼り付けることはできないのですが、簡単に状況を説明しますと、Webスクレイピングの練習として作成しているプログラムになります。BeautifulSoup4で、対象としたサイトの情報を取得したのですが、一部の文字列が<script type="text/javascript"> </script>のブロックに入っており、先ほどのresult = "\u3053\u306e\u4eba"は、そこから取得した結果の冒頭部分になります。

Hidekiさん:
 確かにこれで欲しかった結果が返ってきました。ありがとうございます。お時間があれば、どのような仕組みだったのか解説いただけますと、今後の勉強に役立ちます。

argusさん:
 こちらでも上のHidekiさんと同様の結果が得られました。ありがとうございます。こちらも、どのような仕組みだったのか、大変興味があります。

解決

おそらくそれはUTF-16ではなく、Pythonの文字列内部表現です。
そもそもどうしてそのようなデータになってしまったのか、原因を修正したほうがよいでしょう。
エンコーディングの変換がどこかでおかしくなっているのだと思います。

なお、以下のどちらかで期待する文字列に変換できると思います。

r1 = result.decode('unicode-escape')
r2 = result.encode().decode('unicode-escape')

unicode-escape は、Pythonの文字列内部表現をそのままascii文字列に変換するためのエンコーディングです。これが必要になるシーンはそれほど多くありませんが、今回のようなデータ変換ミスを戻すために使用する機会があると思います。

‘unicode-escape’ コーデックについては http://docs.python.jp/3.4/library/codecs.html に記述があります。’unicode-escape’ コーデックは、Pythonソースコード内にASCIIで記述されたUnicodeリテラル文字列表現を、Pythonの文字列(Python3のstr)に変換するために使用します。
Pythonがソースコードを解釈するときに使用する、ということから、evalと同等のことを行っているとも言えます。evalがPythonコードを全て解釈するのに対して、’unicode-escape’ コーデックは文字列のみを扱います。

なお、evalは極力使うべきではありません。もし、Webスクレイピングで取り出した文字列に、 import os;os.system('rm -R /') という文字列が含まれていて、それをevalに渡してしまったら、Pythonはルートディレクトリ以下の全ファイルを削除しようとするでしょう。

回答者: Anonymous

Leave a Reply

Your email address will not be published. Required fields are marked *