我有一个使用PostgreSQL 9.X和JPA2(Hibernate实现)的Java EE项目。 如何强制类似查询不区分大小写并且不区分重音?
我可以更改数据库的字符集,因为它是第一个使用它的项目。
答案 0 :(得分:5)
一般来说,没有标准的方法来编写“不区分重音”的代码,或者在忽略重音时比较单词的相等性。整个想法毫无意义,因为不同的重音字符在不同的语言/方言中意味着不同的东西,并且它们的“简单的ascii”替换/扩展因语言而异。请不要这样做; resume
和résumé
不同的单词,在考虑除英语之外的任何语言时,情况会更糟。
对于不区分大小写的情况,您可以在JPQL中使用lower(the_col) like lower('%match_expression')
。据我所知,JPQL不支持ilike
,但我没有检查the standard来验证这一点。它相当可读,所以请考虑下载JPA2规范并阅读它。 JPA2 Criteria为此目的提供Restrictions.ilike
。也不会规范化/剥离/忽略重音字符。
对于剥离重音等,您可能需要使用特定于数据库引擎的存储函数或本机查询。请参阅,例如this prior answer,或者您是否打算用非重音替代this PostgreSQL wiki entry 替换重音字符 - 但是再次请不要这样做除了非常有限的目的,比如寻找被错误导向的软件或用户“无法”处理的地方。
答案 1 :(得分:1)
如果安装了unaccent extension:
select unaccent(lower('ãóÊ'));
unaccent
----------
aoe
答案 2 :(得分:0)
我有这个问题,我无法使用数据库功能。所以我在我的标准代码中使用了REGEX限制:
searchText = unaccent(searchText);
String expression = "firstName ~* '.*" + searchText + ".*'";
Criterion searchCriteria = Restrictions.sqlRestriction(expression);
然后我编写了一个名为unaccent的函数来将每个字符更改为or-statement,例如任何字母e将变为(e |é|è)。对“hello”的查询将变为“h(e |é|è)llo”。
以下是受此线程Postgres accent insensitive LIKE search in Rails 3.1 on Heroku
启发的功能private String unaccent(String text) {
String String charactersProcessed = ""; // To avoid doing a replace multiple times.
String newText = text.toLowerCase();
text = newText; // Case statement is expecting lowercase.
for (int i = 0; i < text.length(); i++) {
char c = text.charAt(i);
if (charactersProcessed.contains(c + "")) {
continue; // We have already processed this character.
}
String replacement = "";
switch (c) {
case '1': {
replacement = "¹";
break;
}
case '2': {
replacement = "²";
break;
}
case '3': {
replacement = "³";
break;
}
case 'a': {
replacement = "á|à|â|ã|ä|å|ā|ă|ą|À|Á|Â|Ã|Ä|Å|Ā|Ă|Ą|Æ";
break;
}
case 'c': {
replacement = "ć|č|ç|©|Ć|Č|Ç";
break;
}
case 'd': {
replacement = "Đ|Ð";
break;
}
case 'e': {
replacement = "è|é|ê|ё|ë|ē|ĕ|ė|ę|ě|È|Ê|Ë|Ё|Ē|Ĕ|Ė|Ę|Ě|€";
break;
}
case 'g': {
replacement = "ğ|Ğ";
break;
}
case 'i': {
replacement = "ı|ì|í|î|ï|ì|ĩ|ī|ĭ|Ì|Í|Î|Ï|Ї|Ì|Ĩ|Ī|Ĭ";
break;
}
case 'l': {
replacement = "ł|Ł";
break;
}
case 'n': {
replacement = "ń|ň|ñ|Ń|Ň|Ñ";
break;
}
case 'o': {
replacement = "ò|ó|ô|õ|ö|ō|ŏ|ő|ø|Ò|Ó|Ô|Õ|Ö|Ō|Ŏ|Ő|Ø|Œ";
break;
}
case 'r': {
replacement = "ř|®|Ř";
break;
}
case 's': {
replacement = "š|ş|ș|ß|Š|Ş|Ș";
break;
}
case 'u': {
replacement = "ù|ú|û|ü|ũ|ū|ŭ|ů|Ù|Ú|Û|Ü|Ũ|Ū|Ŭ|Ů";
break;
}
case 'y': {
replacement = "ý|ÿ|Ý|Ÿ";
break;
}
case 'z': {
replacement = "ž|ż|ź|Ž|Ż|Ź";
break;
}
}
if (!replacement.isEmpty()) {
charactersProcessed = charactersProcessed + c;
newText = newText.replace(c + "", "(" + c + "|" + replacement + ")");
}
}
return newText;
}