web-dev-qa-db-ja.com

Postgresデータベースのエンコーディングの問題

正しくエンコードされていないデータをテーブルから変換するように努力しています。たとえば、NadègeNadègeであるフィールドがあります。

Postgresの関数convertconvert_fromconvert_toを試してみましたが、あまりうまくいきませんでした。

db=# SHOW client_encoding;
 client_encoding 
-----------------
 UTF8
(1 row)

db=# SHOW server_encoding;
 server_encoding 
-----------------
 UTF8
(1 row)

db=# SELECT "firstName", encode("firstName"::bytea, 'hex') FROM contact;       
 firstName |       encode       
-----------+--------------------
 Nadège    | 4e6164c3a86765
 Nadège   | 4e6164c383c2a86765
(2 rows)

db=# SELECT "firstName", convert_from("firstName"::bytea, 'latin1') FROM contact WHERE "lastName" ILIKE 'crochard';
 firstName |  convert_from  
-----------+----------------
 Nadège    | Nadège
 Nadège   | NadÃ\u0083¨ge
(2 rows)

db=# SELECT "firstName", convert("firstName"::bytea, 'utf8', 'latin1') FROM contact;                                                                                                                                                       
 firstName |     convert      
-----------+------------------
 Nadège    | \x4e6164e86765
 Nadège   | \x4e6164c3a86765
(2 rows)

pythonを使用すると、次のコマンドで正しいエンコーディングを取得できます。

data.encode('latin1').decode('utf8')

これらの誤ってエンコードされたデータをpostgresで変換する方法に関するヒントはありますか?

4
Cyrbil

あなたが正しく識別したように、_Nadège_はISO_8859-1( "latin-1")として誤ってデコードされた_Nadège_のUTF-8表現です。次に、あなたのケースでは、DBに格納するためにUTF-8に再エンコードします。

それを修正するには、次のことを行う必要があります。

  • 現在の表現を受け取り、UTF-8をバイト文字列としてlatin-1にデコードします。
  • バイト文字列を再解釈し、それをutf-8としてデコードします

そう:

_test=> SELECT convert_from(convert_to('Nadège', 'latin-1'), 'utf-8');
 convert_from 
--------------
 Nadège
(1 row)
_

Python同等のものは、あなたが書いたものに近いでしょうが、PostgreSQLがデータベースエンコーディングにすべてを格納することを示すために、Unicode表現で始まります。

_>>> print u"Nadège".encode("latin-1").decode("utf-8")
Nadège
_

試行されたすべてのソリューションの問題は、textからbyteaへのキャストがデータベースエンコーディングを使用であることです。つまり、utf-8のutf-8表現のバイトは、latin-1として誤ってデコードされています。キャストでは、次のように記述する必要があります。

_test=> SELECT convert_from(convert_to(convert_from((TEXT 'Nadège')::bytea, 'utf-8'), 'latin-1'), 'utf-8');
 convert_from 
--------------
 Nadège
(1 row)
_

latin-1として再解釈して再度デコードする前に、キャストによって生成されたutf-8表現を明示的にデコードする必要があるためです。

_mycol::bytea_の代わりにconvert_to(mycol, 'latin-1')を使用する必要があるだけです

2
Craig Ringer