回答:
java.text.Normalizer
これを処理するために使用します。
string = Normalizer.normalize(string, Normalizer.Form.NFD);
// or Normalizer.Form.NFKD for a more "compatable" deconstruction
これにより、すべてのアクセント記号が文字から分離されます。次に、各文字を文字であるかどうかを比較し、そうでないものを捨てるだけです。
string = string.replaceAll("[^\\p{ASCII}]", "");
テキストがUnicodeの場合は、代わりにこれを使用する必要があります。
string = string.replaceAll("\\p{M}", "");
unicodeの場合\\P{M}
、ベースグリフに一致し、\\p{M}
(小文字)は各アクセントに一致します。
ポインタを提供してくれたGarretWilsonと、優れたUnicodeガイドを提供してくれたregular-expressions.infoに感謝します。
string.replaceAll("\\p{M}", "")
。詳細については、regular-expressions.info / unicode.htmlを参照してください。
2011年以降、Apache Commons StringUtils.stripAccents(input)を使用できます(3.0以降):
String input = StringUtils.stripAccents("Tĥïŝ ĩš â fůňķŷ Šťŕĭńġ");
System.out.println(input);
// Prints "This is a funky String"
注意:
受け入れられた回答(Erick Robertson's)は、Øまたはforでは機能しません。Apache Commons 3.5はØでも機能しませんが、Łでは機能します。WikipediaのØに関する記事を読んだ後、「O」に置き換える必要があるかどうかはわかりません。これは、ノルウェー語とデンマーク語の別の文字で、「z」の後にアルファベット順になっています。これは、「ストリップアクセント」アプローチの制限の良い例です。
@ virgo47によるソリューションは非常に高速ですが、概算です。受け入れられた答えはノーマライザと正規表現を使用しています。正規表現を使用せずにすべての非ASCII文字を削除できるため、Normalizerと正規表現で時間のどの部分が費やされたのか疑問に思いました。
import java.text.Normalizer;
public class Strip {
public static String flattenToAscii(String string) {
StringBuilder sb = new StringBuilder(string.length());
string = Normalizer.normalize(string, Normalizer.Form.NFD);
for (char c : string.toCharArray()) {
if (c <= '\u007F') sb.append(c);
}
return sb.toString();
}
}
コードの明快さの低下がメリットになるかどうかはわかりませんが、char []に書き込んでtoCharArray()を呼び出さないようにすることで、追加の小さな高速化を実現できます。
public static String flattenToAscii(String string) {
char[] out = new char[string.length()];
string = Normalizer.normalize(string, Normalizer.Form.NFD);
int j = 0;
for (int i = 0, n = string.length(); i < n; ++i) {
char c = string.charAt(i);
if (c <= '\u007F') out[j++] = c;
}
return new String(out);
}
このバリエーションには、ノーマライザを使用するものの正確さと、テーブルを使用するものの速度の一部の利点があります。私のマシンでは、これは受け入れられた回答よりも約4倍速く、@ virgo47の6.6倍から7倍遅くなっています(受け入れられた回答は、私のマシンの@ virgo47の約26倍遅いです)。
out
j
文字列オブジェクトの作成に使用する前に、有効な文字数に合わせてサイズを変更する必要があります。
flattenToAscii
は結果 "aa .."を作成します。ここで、ドットは\ u0000を表します。それは良くない。最初の質問は、「正規化できない」文字をどのように表すかです。それが?になるとしましょう、またはそこにNULL文字を残すことができますが、いずれの場合も(正規表現ソリューションのように)これらの正しい位置を保持する必要があります。このため、ループ内のifは次のようなものif (c <= '\u007F') out[j++] = c; else if (Character.isLetter(c)) out[j++] = '?';
でなければなりません。少し遅くなりますが、そもそも正しいはずです。;-)
isLetter
)は適切なものではないかもしれませんが、私はそれを見つけられませんでした。私はUnicodeの専門家ではないので、元の文字を置き換える単一の文字のクラスを特定する方法がわかりません。文字はほとんどのアプリケーション/使用法で問題なく機能します。
編集:Java <6に悩まされておらず、速度が重要でない場合や変換テーブルの制限が多すぎる場合は、Davidの回答を使用してください。ポイントはNormalizer
、ループ内で変換テーブルの代わりに(Java 6で導入された)を使用することです。
これは「完全な」解決策ではありませんが、範囲(この場合はLatin1、2)がわかっていて、Java 6より前に動作していて(実際の問題ではありません)、最も推奨されるバージョンよりもはるかに高速です(多かれ少なかれかもしれません)問題ではない):
/**
* Mirror of the unicode table from 00c0 to 017f without diacritics.
*/
private static final String tab00c0 = "AAAAAAACEEEEIIII" +
"DNOOOOO\u00d7\u00d8UUUUYI\u00df" +
"aaaaaaaceeeeiiii" +
"\u00f0nooooo\u00f7\u00f8uuuuy\u00fey" +
"AaAaAaCcCcCcCcDd" +
"DdEeEeEeEeEeGgGg" +
"GgGgHhHhIiIiIiIi" +
"IiJjJjKkkLlLlLlL" +
"lLlNnNnNnnNnOoOo" +
"OoOoRrRrRrSsSsSs" +
"SsTtTtTtUuUuUuUu" +
"UuUuWwYyYZzZzZzF";
/**
* Returns string without diacritics - 7 bit approximation.
*
* @param source string to convert
* @return corresponding string without diacritics
*/
public static String removeDiacritic(String source) {
char[] vysl = new char[source.length()];
char one;
for (int i = 0; i < source.length(); i++) {
one = source.charAt(i);
if (one >= '\u00c0' && one <= '\u017f') {
one = tab00c0.charAt((int) one - '\u00c0');
}
vysl[i] = one;
}
return new String(vysl);
}
32ビットJDKを使用した私のハードウェアでのテストでは、Normalizerの方法で3.7秒(37倍遅い)の間に100ミリ秒でàèéàšťč89FDČからaeelstc89FDCへの変換が100万回実行されることが示されています。あなたのニーズがパフォーマンスに関連していて、入力範囲がわかっている場合、これはあなたのためかもしれません。
楽しい :-)
System.out.println(Normalizer.normalize("àèé", Normalizer.Form.NFD).replaceAll("\\p{InCombiningDiacriticalMarks}+", ""));
私のために働いた。上記のスニペットの出力は、私が欲しかった「aee」を与えますが、
System.out.println(Normalizer.normalize("àèé", Normalizer.Form.NFD).replaceAll("[^\\p{ASCII}]", ""));
代用をしませんでした。
言語によっては、アクセント(文字の音を変える)とは見なされない場合がありますが、発音区別符号
https://en.wikipedia.org/wiki/Diacritic#Languages_with_letters_taining_diacritics
「ボスニア語とクロアチア語には記号č、ć、đ、š、およびhaveがあり、これらは別々の文字と見なされ、辞書および単語がアルファベット順にリストされている他のコンテキストでそのようにリストされています。」
それらを削除すると、本質的に単語の意味が変わったり、文字が完全に異なるものに変わったりすることがあります。
文字列の等価性チェックに関連する同じ問題に直面しました。比較する文字列の1つに ASCII文字コード128-255があります。
つまり、改行なしスペース-[Hex-A0]スペース[Hex-20]。HTMLで改行しないスペースを表示します。以下を使用しました
spacing entities
。彼らの性格とそのバイトは&emsp is very wide space[ ]{-30, -128, -125}, &ensp is somewhat wide space[ ]{-30, -128, -126}, &thinsp is narrow space[ ]{32} , Non HTML Space {}
String s1 = "My Sample Space Data", s2 = "My Sample Space Data"; System.out.format("S1: %s\n", java.util.Arrays.toString(s1.getBytes())); System.out.format("S2: %s\n", java.util.Arrays.toString(s2.getBytes()));
バイト単位の出力:
S1:[77、121
32
、83、97、109、112、108、101、32
83、112、97、99、101、32
68、97、116、97] S2:[77、121-30, -128, -125
、83、 97、109、112、108、101、-30, -128, -125
83、112、97、99、101、-30, -128, -125
68、97、116、97]
さまざまなスペースとそのバイトコードに以下のコードを使用します。 wiki for List_of_Unicode_characters
String spacing_entities = "very wide space,narrow space,regular space,invisible separator";
System.out.println("Space String :"+ spacing_entities);
byte[] byteArray =
// spacing_entities.getBytes( Charset.forName("UTF-8") );
// Charset.forName("UTF-8").encode( s2 ).array();
{-30, -128, -125, 44, -30, -128, -126, 44, 32, 44, -62, -96};
System.out.println("Bytes:"+ Arrays.toString( byteArray ) );
try {
System.out.format("Bytes to String[%S] \n ", new String(byteArray, "UTF-8"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
Java Java用のUnicode文字列のASCII文字変換。 unidecode
String initials = Unidecode.decode( s2 );
➩使用Guava
:GoogleのコアをLibraries for Java
。
String replaceFrom = CharMatcher.WHITESPACE.replaceFrom( s2, " " );
スペースの URLエンコードには、 Guavaライブラリを使用します。
String encodedString = UrlEscapers.urlFragmentEscaper().escape(inputString);
some String.replaceAll()
一部で使用されているこの問題を克服するためRegularExpression
。
// \p{Z} or \p{Separator}: any kind of whitespace or invisible separator.
s2 = s2.replaceAll("\\p{Zs}", " ");
s2 = s2.replaceAll("[^\\p{ASCII}]", " ");
s2 = s2.replaceAll(" ", " ");
java java.text.Normalizer.Formを使用する。この列挙型は、Unicode Standard Annex#15 — Unicode正規化フォームとそれらにアクセスするための2つのメソッドで説明されている4つのUnicode正規化フォームの定数を提供します。
s2 = Normalizer.normalize(s2, Normalizer.Form.NFKC);
ide Unidecode、Normalizer、StringUtilsなどのさまざまなアプローチで文字列と出力をテストします。
String strUni = "Tĥïŝ ĩš â fůňķŷ Šťŕĭńġ Æ,Ø,Ð,ß";
// This is a funky String AE,O,D,ss
String initials = Unidecode.decode( strUni );
// Following Produce this o/p: Tĥïŝ ĩš â fůňķŷ Šťŕĭńġ Æ,Ø,Ð,ß
String temp = Normalizer.normalize(strUni, Normalizer.Form.NFD);
Pattern pattern = Pattern.compile("\\p{InCombiningDiacriticalMarks}+");
temp = pattern.matcher(temp).replaceAll("");
String input = org.apache.commons.lang3.StringUtils.stripAccents( strUni );
Unidecodeの使用は、best choice
以下に示す私の最後のコードです。
public static void main(String[] args) {
String s1 = "My Sample Space Data", s2 = "My Sample Space Data";
String initials = Unidecode.decode( s2 );
if( s1.equals(s2)) { //[ , ] %A0 - %2C - %20 « http://www.ascii-code.com/
System.out.println("Equal Unicode Strings");
} else if( s1.equals( initials ) ) {
System.out.println("Equal Non Unicode Strings");
} else {
System.out.println("Not Equal");
}
}
Junidecodeをお勧めします。'Ł'と 'Ø'だけでなく、中国語などの他のアルファベットからラテンアルファベットへの文字変換にも有効です。
@David Conradソリューションは、ノーマライザを使用して試した最速ですが、バグがあります。基本的にアクセントではない文字を取り除きます。たとえば、中国語の文字やæのような他の文字はすべて取り除かれます。削除する文字は非スペースマークです。これは、最終的な文字列で余分な幅を使用しない文字です。これらの幅がゼロの文字は、基本的に他の文字に結合されます。たとえば、この `のように、それらが文字として分離されていることがわかる場合、それはスペース文字と組み合わされていると思います。
public static String flattenToAscii(String string) {
char[] out = new char[string.length()];
String norm = Normalizer.normalize(string, Normalizer.Form.NFD);
int j = 0;
for (int i = 0, n = norm.length(); i < n; ++i) {
char c = norm.charAt(i);
int type = Character.getType(c);
//Log.d(TAG,""+c);
//by Ricardo, modified the character check for accents, ref: http://stackoverflow.com/a/5697575/689223
if (type != Character.NON_SPACING_MARK){
out[j] = c;
j++;
}
}
//Log.d(TAG,"normalized string:"+norm+"/"+new String(out));
return new String(out);
}
ライブラリがない場合に正規表現とノーマライザを使用する最良の方法の1つは次のとおりです。
public String flattenToAscii(String s) {
if(s == null || s.trim().length() == 0)
return "";
return Normalizer.normalize(s, Normalizer.Form.NFD).replaceAll("[\u0300-\u036F]", "");
}
これはreplaceAll( "[^ \ p {ASCII}]"、 ""))よりも効率的です。 あり、発音区別符号が必要ない場合例のように)。
それ以外の場合は、p {ASCII}パターンを使用する必要があります。
よろしく。
最善の解決策は、各文字をHEXに変換し、それを別のHEXに置き換えることです。これは、2つのUnicode入力があるためです。
Composite Unicode
Precomposed Unicode
たとえば、Composite Unicodeで記述された「Ồ」は、Precomposed Unicodeで記述された「Ồ」とは異なります。私のサンプル文字をコピーして変換して、違いを確認できます。
In Composite Unicode, "Ồ" is combined from 2 char: Ô (U+00d4) and ̀ (U+0300)
In Precomposed Unicode, "Ồ" is single char (U+1ED2)
一部の銀行がコアバンクに送信する前に情報を変換するためにこの機能を開発しました(通常はUnicodeをサポートしていません)。エンドユーザーが複数のUnicode入力を使用してデータを入力するときにこの問題に直面しました。したがって、HEXに変換して置き換えることが最も信頼できる方法だと思います。
誰かがkotlinでこれを行うために苦労している場合、このコードは魅力のように機能します。不整合を避けるために、.toUpperCaseとTrim()も使用します。次に、この関数をキャストします。
fun stripAccents(s: String):String{
if (s == null) {
return "";
}
val chars: CharArray = s.toCharArray()
var sb = StringBuilder(s)
var cont: Int = 0
while (chars.size > cont) {
var c: kotlin.Char
c = chars[cont]
var c2:String = c.toString()
//these are my needs, in case you need to convert other accents just Add new entries aqui
c2 = c2.replace("Ã", "A")
c2 = c2.replace("Õ", "O")
c2 = c2.replace("Ç", "C")
c2 = c2.replace("Á", "A")
c2 = c2.replace("Ó", "O")
c2 = c2.replace("Ê", "E")
c2 = c2.replace("É", "E")
c2 = c2.replace("Ú", "U")
c = c2.single()
sb.setCharAt(cont, c)
cont++
}
return sb.toString()
}
これらの楽しみを使用するには、次のようにコードをキャストします。
var str: String
str = editText.text.toString() //get the text from EditText
str = str.toUpperCase().trim()
str = stripAccents(str) //call the function