Postgresql 和 UTF8 到 Latin1 的转换?

Jam*_*own 6 postgresql bytea

我们有一个 Postgresql 数据库,其中数据在 Latin1 中。显然有人将一些 UTF8 编码的数据加载到其中,因为当我从某些列中选择数据时,我得到如下内容:

SELECT symptoms from client
- -
"huvudvärke"
- -
Run Code Online (Sandbox Code Playgroud)

其中“ä”应该是“ä”。我可以用替换来处理它,即:

UPDATE client SET symptoms=replace(symptoms, 'ä', 'ä');
Run Code Online (Sandbox Code Playgroud)

我尝试了几个我找到的解决方案,比如使用convert和 ,convert_to但这使数据看起来像"huvudv\303\244rke".

我的问题有现有的解决方案吗?

编辑:

SELECT symptoms, symptoms::bytea from client
- -
"huvudvärke";"huvudv\303\203\302\244rke" 
- -
Run Code Online (Sandbox Code Playgroud)

在上面的 UPDATE 之后,查询症状::bytea 输出:

SELECT symptoms, symptoms::bytea from client
- -
"huvudvärke";"huvudv\303\244rke" 
- -
Run Code Online (Sandbox Code Playgroud)

编辑2:

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"
Run Code Online (Sandbox Code Playgroud)

Cra*_*ger 10

看起来您使用的任何客户端都对文本编码感到困惑;它可能发送 utf-8 字节,就好像它们是 latin-1 一样。

查看:

  • SHOW client_encoding;
  • SHOW server_encoding;
  • locale 命令在您的终端,如果使用 psql

update正在用八进制字节替换\303\244“ä”(U+00E4)的 utf-8 编码。您没有在您认为的位置替换 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)
Run Code Online (Sandbox Code Playgroud)

不仅如此,replace如果替换目标是解释为 latin-1的utf-8 编码字节序列,则您只能首先匹配。ä\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)
Run Code Online (Sandbox Code Playgroud)

有你的解释。

我想说您可能已经在数据库中有一堆错误编码的数据,并且您注意到了这个,因为它被损坏了两次。您可能正在做一些类似于将 utf-8 字节常规干扰到 latin-1 编码字段的事情,但您通常会侥幸逃脱,因为您再次将它们解码为 utf-8 - 这一次您做了一些不同的事情。

如果您想将损坏的文本转换为原始文本,您只需反转不正确的编码过程。解码 utf-8 并输出 latin-1,然后将 latin-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)
Run Code Online (Sandbox Code Playgroud)