Answers:
使用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的指针和regular-expressions.info为伟大的Unicode指南。
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)不适用于Ø或Ł。Apache Commons 3.5也不适用于Ø,但适用于Ł。阅读Ø的Wikipedia文章后,我不确定是否应将其替换为“ O”:它是挪威语和丹麦语中的单独字母,在“ z”之后按字母顺序排列。这是“条带重音”方法局限性的一个很好的例子。
@ virgo47的解决方案非常快,但是是近似的。接受的答案使用Normalizer和正则表达式。我想知道Normalizer和正则表达式花了什么时间,因为删除所有非ASCII字符可以不用正则表达式来完成:
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);
}
这种变化的优点是使用Normalizer的正确性和使用表的速度的某些优点。在我的机器上,这个速度比接受的答案快4倍,比@ virgo47的速度慢6.6倍至7倍(接受的答案比我的机器上的@ virgo47慢26倍)。
out
j
在构造字符串对象之前,必须调整大小以匹配有效字符的数量。
flattenToAscii
会创建结果“ aa ..”,其中点表示\ u0000。这是不好的。第一个问题是-如何表示“无法标准化”的字符?假设它是?,或者我们可以在此处保留NULL char,但是无论如何我们都必须保留它们的正确位置(就像regex解决方案一样)。为此,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在我的硬件上进行的测试表明,该程序可以在约100ms的时间内将àèéľšťč89FDČ转换为aeelstc89FDC 100万次,而Normalizer的转换速度为3.7s(慢37倍)。如果您的需求围绕性能,并且您知道输入范围,那么这可能适合您。
请享用 :-)
System.out.println(Normalizer.normalize("àèé", Normalizer.Form.NFD).replaceAll("\\p{InCombiningDiacriticalMarks}+", ""));
为我工作。上面代码段的输出给出了“ aee”,这是我想要的,但是
System.out.println(Normalizer.normalize("àèé", Normalizer.Form.NFD).replaceAll("[^\\p{ASCII}]", ""));
没有做任何替换。
根据语言的不同,这些可能不会被视为重音符号(这会改变字母的发音),而是变音符号
https://zh.wikipedia.org/wiki/Diacritic#Languages_with_letters_ contains_diacritics
“波斯尼亚语和克罗地亚语的符号分别是č,ć,đ,š和ž,它们被认为是单独的字母,并且在字典和其他上下文中也按字母顺序列出,因此也是如此。”
删除它们可能会从本质上改变单词的含义,或将字母更改为完全不同的字母。
我曾经遇到过与字符串相等性检查相关的相同问题,比较字符串之一具有 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();
}
for Java的Unicode字符串的ASCII音译。 unidecode
String initials = Unidecode.decode( s2 );
➩使用Guava
:Google Core Libraries for Java
。
String replaceFrom = CharMatcher.WHITESPACE.replaceFrom( s2, " " );
String encodedString = UrlEscapers.urlFragmentEscaper().escape(inputString);
➩为了克服这个问题使用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.text.Normalizer.Form。该枚举提供了Unicode标准附件#15 — Unicode规范化形式中描述的四种Unicode规范化形式的常量,以及访问它们的两种方法。
s2 = Normalizer.normalize(s2, Normalizer.Form.NFKC);
使用不同的方法(如Unidecode,Normalizer,StringUtils)测试String和输出。
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解决方案是我尝试使用Normalizer最快的解决方案,但确实存在错误。它基本上会去除不带重音符号的字符,例如汉字和其他字母(如æ)都被去除。我们要剥离的字符是非空格标记,这些字符在最终字符串中不会占用额外的宽度。这些零宽度字符基本上最终以其他字符组合在一起。如果您可以看到它们被孤立为一个字符(例如,像`这样的字符),那么我猜是它与空格字符结合在一起了。
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);
}
如果没有库,使用正则表达式和规范化器的最佳方法之一是:
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}模式。
问候。
我认为最好的解决方案是将每个字符转换为十六进制并用另一个十六进制替换。这是因为有2种Unicode类型:
Composite Unicode
Precomposed Unicode
例如,复合Unicode编写的“Ồ”与预组合Unicode编写的“Ồ”不同。您可以复制我的示例字符并将其转换以查看区别。
In Composite Unicode, "Ồ" is combined from 2 char: Ô (U+00d4) and ̀ (U+0300)
In Precomposed Unicode, "Ồ" is single char (U+1ED2)
我已经为某些银行开发了此功能,以便在将信息发送到核心银行之前转换信息(通常不支持Unicode),并且当最终用户使用多种Unicode类型输入数据时会遇到此问题。因此,我认为转换为十六进制并替换它是最可靠的方法。
万一有人在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