web-dev-qa-db-ja.com

PostgresqlとUTF8からLatin1への変換?

データがLatin1にあるPostgresqlデータベースがあります。一部の列からデータを選択すると、次のようなものが表示されるため、誰かがUTF8エンコードされたデータをロードしたようです。

SELECT symptoms from client
- -
"huvudvärke"
- -

ここで、「ä」は「ä」である必要があります。私はそれを置換で処理することができました、すなわち:

UPDATE client SET symptoms=replace(symptoms, 'ä', 'ä');

convertconvert_toを使用するなど、いくつかの解決策を試しましたが、データは"huvudv\303\244rke"のように見えます。

私の問題に対する既存の解​​決策はありますか?

編集:

SELECT symptoms, symptoms::bytea from client
- -
"huvudvärke";"huvudv\303\203\302\244rke" 
- -

上記のUPDATEの後、symptoms :: byteaの出力でクエリを実行します。

SELECT symptoms, symptoms::bytea from client
- -
"huvudvärke";"huvudv\303\244rke" 
- -

EDIT2:

select version();
"PostgreSQL 9.2.9, compiled by Visual C++ build 1600, 64-bit"

show client_encoding; --I'm using pgAdmin III 1.18.1
"UNICODE"

show server_encoding;
"UTF8"

SELECT symptoms, convert(convert_to(symptoms, 'utf-8'), 'latin-1', 'utf-8')::text from client;
"huvudvärke","huvudv\303\203\302\203\303\202\302\244rke"
4
James Brown

使用しているクライアントがテキストエンコーディングについて混乱しているようです。おそらくラテン-1のようにutf-8バイトを送信しています。

小切手:

  • SHOW client_encoding;
  • SHOW server_encoding;
  • localeを使用している場合は、ターミナルでpsqlコマンド

あなたのupdateは8進バイト\303\244を "ä"のutf-8エンコーディングに置き換えています(U + 00E4)。自分が思っている場所で、latin-1でエンコードされたデータを置き換えているわけではありません。

観察する:

regress=> SELECT convert_from(BYTEA 'huvudv\303\244rke', 'latin-1');
 convert_from 
--------------
 huvudvärke
(1 row)

regress=> SELECT convert_from(BYTEA 'huvudv\303\244rke', 'utf-8');
 convert_from 
--------------
 huvudvärke
(1 row)

それだけでなく、replaceが最初に一致したのは、置換ターゲットがtf-8エンコード済みäのバイトシーケンスであり、latin-1として解釈された場合のみです。 、つまり\303\203\302\244

Pgのバージョン、使用しているクライアントなどの詳細がないと、より具体的に特定することは困難ですが、根本的な原因は、クライアントがI/Oのエンコーディングでまったく問題を抱えていることです。

元のテキストは完全に破損しているため、UTF-8またはlatin-1では無効です。誰かがいくつかのUTF-8データを取得し、それをlatin-1としてデコードしてから、もう一度utf-8としてエンコードしたようです。

うん、確かに:

regress=> SELECT convert(convert_to('huvudvärke', 'utf-8'), 'latin-1', 'utf-8');
          convert          
---------------------------
 huvudv\303\203\302\244rke
(1 row)

あなたの説明があります。

おそらく、すでにDBに誤ってエンコードされたデータの束がたくさんあると思いますが、このデータに気づかれたのはtwiceであるためです。あなたはおそらく日常的にutf-8バイトをlatin-1でエンコードされたフィールドに詰め込むようなことをしていますが、通常はそれらをutf-8として再びデコードするのでそれを回避します-そして今度は何か違うことをしました。

マングルされたテキストを元のテキストに戻したい場合は、間違ったエンコードプロセスを元に戻すだけです。 utf-8をデコードし、latin-1を出力してから、latf-1をutf-8として再インタペットして、もう一度デコードします。例:

regress=> SELECT  convert_from(convert(BYTEA 'huvudv\303\203\302\244rke', 'utf-8', 'latin-1'), 'utf-8');
 convert_from 
--------------
 huvudvärke
(1 row)
7
Craig Ringer

文字列をdest_encodingに変換します。元のエンコーディングはsrc_encodingで指定されます。文字列はこのエンコーディングで有効でなければなりません。変換はCREATE CONVERSIONで定義できます。また、いくつかの定義済みの変換があります。使用可能な変換については、表9-7を参照してください。

参照 その他の文字列関数

convert(string bytea, src_encoding name, dest_encoding name)
convert_to(text_in_database,'LATIN1')
0
Heisenberg