重温德国变音符号和UTF8校对

时间:2014-01-06 15:43:32

标签: mysql collation diacritics

我相信很多人都知道,至少可以说,不得不处理德语变音符号和UTF8校对可能会有问题。像a = äo = öu = ü这样的东西不仅能够影响结果的排序顺序,还能影响实际结果。这是一个例子,通过简单地尝试区分名词的单数和复数形式(Bademantel - 单数,Bademäntel - 复数),可以清楚地说明事情是如何出错的。

CREATE TABLE keywords (
    id INT (11) PRIMARY KEY AUTO_INCREMENT,
    keyword VARCHAR (255) NOT NULL
) ENGINE = MyISAM DEFAULT CHARACTER
SET = utf8 COLLATE = utf8_unicode_ci;

INSERT INTO keywords (keyword) VALUES ('Bademantel'), ('Bademäntel');

SELECT * FROM keywords WHERE keyword LIKE ('%Bademäntel%');

结果应该是

+----+------------+
| id | keyword    |
+----+------------+
|  1 | Bademäntel |
+----+------------+

utf8_unicode_ci输出

+----+------------+
| id | keyword    |
+----+------------+
|  1 | Bademantel |
|  2 | Bademäntel |
+----+------------+

这显然不是必需的结果。

实际问题与我当前的项目有关。它涉及编写一个关键字解析器,它基本上应该用一个指向相应产品页面的链接替换网站上每个关键字的出现。为了避免不必要的资源浪费,只能使用

获取不同的关键字
SELECT keyword FROM keywords GROUP BY keyword ORDER BY LENGTH(keyword) DESC

SELECT DISTINCT keyword FROM keywords ORDER BY LENGTH(keyword) DESC

将导致无法处理(链接)单词的所有非变音版本,因为它们在查询期间未被提取(即将提取包含Bademäntel的所有关键字,但Bademantel将被省略。)

现在我意识到我有几个选择来解决这个问题。

1)对关键字表或在查询期间使用utf8_swedish_ci,这将有效地使我免于修改大量现有代码。

SELECT DISTINCT keyword COLLATE utf8_swedish_ci AS keyword FROM keywords ORDER BY LENGTH(keyword) DESC;

不幸的是,我并不愿意放弃utf8_unicode_ci,因为a)它提供了一个非常好的排序功能“Eszett”(ssß被认为是相同的),b)不知何故,使用瑞典语校对处理德语相关的东西只是感觉不对。

2)修改现有代码以使用utf8_bin

SELECT DISTINCT keyword COLLATE utf8_bin AS keyword FROM keywords ORDER BY LENGTH(keyword) DESC;

这是按预期工作但它有一个令人讨厌的缺点,所有比较都区分大小写,这意味着如果我决定依靠utf8_bin作为问题的解决方案,我将很难做不区分大小写像LIKE('%Mäntel%')这样的查询肯定会省略像Bademäntel这样的记录。

我知道这个问题时不时地出现在SO上,但是现在有些答案已经很老了,我只是想知道是否还有其他解决方案可能同时出现。我的意思是,我真的无法想象允许简单的整理完全改变查询的结果。排序顺序是,但结果本身?

对不起,请稍等一些帖子,并提前感谢任何建议或评论。

2 个答案:

答案 0 :(得分:2)

对于遇到此问题的其他人,值得注意的是since MySQL 5.6正式支持utf8_german2_ci整理解决上述所有问题。迟到了,我猜不到。

答案 1 :(得分:1)

您可以使用关键字WHERE BINARY keyword = 'Bademantel'进行二进制检查。结果将是预期的结果。

查看此sqlfiddle,其中显示了以下内容:

SELECT * FROM stackoverflow WHERE BINARY keyword = 'Bademantel';

| id |    keyword |
|----|------------|
|  1 | Bademantel |

SELECT * FROM stackoverflow WHERE keyword = 'Bademantel';

| id |    keyword |
|----|------------|
|  1 | Bademantel |
|  2 | Bademäntel |

此处有关于此行为的更多信息:What effects does using a binary collation have?和此处:What is the best MySQL collation for German language

因此,对于使用德语变音符号或法语重音符号或捷克语/波兰语特殊字符的应用程序,您必须确定哪种行为最适合您的应用。

大部分情况都适用于utf8_general_ci,但有时您必须使用utf8_bin来处理Bademantel等情况。

字符串比较根本不是很糟糕,utf8_general_ci有时会帮助你。如果您保存了Straße之类的字符串,则可以搜索Strasse,这也会返回Straße