PostgreSQL 9.XとJPA2(Hibernate実装)を使用したJavaEEプロジェクトがあります。同様のクエリで大文字と小文字を区別せず、アクセントを区別しないようにするにはどうすればよいですか?
DBを使用する最初のプロジェクトであるため、DBの文字セットを変更できます。
PostgreSQL 9.XとJPA2(Hibernate実装)を使用したJavaEEプロジェクトがあります。同様のクエリで大文字と小文字を区別せず、アクセントを区別しないようにするにはどうすればよいですか?
DBを使用する最初のプロジェクトであるため、DBの文字セットを変更できます。
一般に、「アクセントを区別しない」コードを記述したり、アクセントを無視して単語を比較したりする標準的な方法はありません。異なるアクセント付き文字は異なる言語/方言で異なることを意味し、それらの「プレーンASCII」置換/拡張は言語によって異なるため、全体のアイデアはほとんど意味がありません. これをしないでください。resume
とrésumé
は別の単語であり、英語以外の言語を考慮すると状況はさらに悪化します。
大文字と小文字を区別しないためlower(the_col) like lower('%match_expression')
に、JPQL で使用できます。私が知る限りilike
、JPQL ではサポートされていませんが、これを確認するために標準をチェックしていません。かなり読みやすいので、JPA2 仕様をダウンロードして読むことを検討してください。JPA2基準はRestrictions.ilike
、目的のために提供しています。どちらも、アクセント付きの文字を正規化/削除/無視しません。
アクセントなどを取り除くには、おそらくデータベース エンジン固有のストアド関数またはネイティブ クエリを使用する必要があります。たとえば、この前の回答を参照するか、アクセント付きの文字をアクセントのない代替のこのPostgreSQL wikiエントリに置き換えることを意図している場合-ただし、単語が「アクセントのない」場所を見つけるなどの非常に限られた目的を除いて、これを行わないでください見当違いのソフトウェアまたはユーザーによって。
アクセントのない拡張機能がインストールされている場合:
select unaccent(lower('ãóÊ'));
unaccent
----------
aoe
この問題があり、データベース機能を使用できませんでした。代わりに、基準コードで REGEX 制限を使用しました。
searchText = unaccent(searchText);
String expression = "firstName ~* '.*" + searchText + ".*'";
Criterion searchCriteria = Restrictions.sqlRestriction(expression);
次に、各文字を or ステートメントに変更する unaccent という関数を作成しました。たとえば、任意の文字 e は (e|é|è) になります。「hello」のクエリは「h(e|é|è)llo」になります。
これは、Heroku の Rails 3.1 でのこのスレッドPostgres アクセントの影響を受けない LIKE 検索から着想を得た関数です。
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;
}