我们有一个 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)