如何在PostgreSQL和JPA 2中做一个不区分大小写和重音不敏感的东西?

时间:2012-10-23 08:42:41

标签: postgresql java-ee jpa-2.0 postgresql-9.1

我有一个使用PostgreSQL 9.X和JPA2(Hibernate实现)的Java EE项目。 如何强制类似查询不区分大小写并且不区分重音?

我可以更改数据库的字符集,因为它是第一个使用它的项目。

3 个答案:

答案 0 :(得分:5)

一般来说,没有标准的方法来编写“不区分重音”的代码,或者在忽略重音时比较单词的相等性。整个想法毫无意义,因为不同的重音字符在不同的语言/方言中意味着不同的东西,并且它们的“简单的ascii”替换/扩展因语言而异。请不要这样做; resumeré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;
}