18

我有大量苏格兰和威尔士口音的地名(结合了严重、急性、抑扬符和 diareses),我需要将其更新为它们的 unicode 规范化形式,例如,较短的形式 00E1 (\xe1)á代替 0061 + 0301 ( \x61\x301)

我从 2009 年的旧 Postgres nabble 邮件列表中找到了一个解决方案,使用 pl/python,

create or replace function unicode_normalize(str text) returns text as $$
  import unicodedata
  return unicodedata.normalize('NFC', str.decode('UTF-8'))
$$ LANGUAGE PLPYTHONU;

正如预期的那样,这很有效,但让我想知道是否有任何方法可以直接使用内置的 Postgres 函数。我使用 convert_to 尝试了各种转换,但都是徒劳的。

编辑:正如克雷格所指出的,我尝试过的一件事是:

SELECT convert_to(E'\u00E1', 'iso-8859-1');

返回\xe1,而

SELECT convert_to(E'\u0061\u0301', 'iso-8859-1');

失败了ERROR: character 0xcc81 of encoding "UTF8" has no equivalent in "LATIN1"

4

1 回答 1

13

我认为这是一个 Pg 错误。

在我看来,PostgreSQL 应该在执行编码转换之前将 utf-8 规范化为预先组合的形式。显示的转换结果是错误的。

我将在 pgsql-bugs 上提出它……完成。

http://www.postgresql.org/message-id/53E179E1.3060404@2ndquadrant.com

您应该能够关注那里的线程。

编辑:pgsql-hackers 似乎不同意,所以这不太可能很快改变。我强烈建议您在应用程序输入边界处规范化您的 UTF-8。

顺便说一句,这可以简化为:

regress=> SELECT 'á' = 'á';
 ?column? 
----------
 f
(1 row)

这是普通的疯狂谈话,但被允许。第一个是预先合成的,第二个不是。(要查看此结果,您必须复制和粘贴,并且仅在您的浏览器或终端未规范化 utf-8 时才有效)。

如果您使用的是 Firefox,您可能无法正确看到上述内容;Chrome 可以正确呈现它。如果您的浏览器正确处理分解的 Unicode,您应该看到以下内容:

分解与预先组合的 unicode á 显示相等的错误

于 2014-08-06T00:03:24.900 回答