Это очень распространенная проблема, с которой мы сталкиваемся, борясь с «таинствами» JavaScript.
Давайте начнем с простой функции JavaScript:
function foo(){
// do something
return 'wohoo';
}
let bar = foo(); // bar is 'wohoo' here
Это простой синхронный вызов функции (где каждая строка кода выполняется одна за другой в последовательность), и результат будет таким же, как ожидалось.
Теперь добавим немного завихрения, введя небольшую задержку в нашей функции, чтобы все строки кода не выполнялись последовательно. Таким образом, он будет эмулировать асинхронное поведение функции:
function foo(){
setTimeout( ()=>{
return 'wohoo';
}, 1000 )
}
let bar = foo() // bar is undefined here
Итак, вы идете, эта задержка просто сломала функциональность, которую мы ожидали! Но что именно произошло? Ну, на самом деле это довольно логично, если вы посмотрите на код. функция foo()
после выполнения ничего не возвращает (таким образом, возвращаемое значение равно undefined
), но оно запускает таймер, который выполняет функцию после 1s, чтобы вернуть «wohoo». Но, как вы можете видеть, значение, присвоенное бару, является немедленно возвращенным материалом из foo (), а не что-либо еще, что приходит позже.
Итак, как мы решаем эту проблему?
Давайте попросим нашу функцию для ОБЕЩАНИЯ. Обещание действительно о том, что это означает: это означает, что функция гарантирует, что вы предоставите любой результат, который он получит в будущем. поэтому давайте посмотрим на это в нашей маленькой проблеме выше:
function foo(){
return new Promise( (resolve, reject) => { // I want foo() to PROMISE me something
setTimeout ( function(){
// promise is RESOLVED , when exececution reaches this line of code
resolve('wohoo')// After 1 second, RESOLVE the promise with value 'wohoo'
}, 1000 )
})
}
let bar ;
foo().then( res => {
bar = res;
console.log(bar) // will print 'wohoo'
});
Таким образом, резюме - для решения асинхронных функций, таких как вызовы на основе ajax и т. д., вы можете использовать обещание resolve
значение (которое вы намерены вернуть). Таким образом, короче говоря, вы разрешаете значение вместо возврата в асинхронных функциях.
Используйте java.text.Normalizer
, чтобы обработать это для вас.
string = Normalizer.normalize(string, Normalizer.Form.NFD);
Это отделит все знаки акцента от символов. Затем вам просто нужно сравнить каждого персонажа с буквой и выбросить те, которые не являются.
string = string.replaceAll("[^\\p{ASCII}]", "");
Если ваш текст находится в юникоде, вы должны использовать это вместо:
string = string.replaceAll("\\p{M}", "");
Для юникода \\P{M}
соответствует базовому глифу, а \\p{M}
(нижний регистр) соответствует каждому акценту.
Благодаря GarretWilson для указателя и regular-expressions.info для большого руководства по юникоду.
Решение @ 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);
}
У этого варианта есть преимущество правильности той, которая используется Нормализатор и часть скорости, используемой таблицей. На моей машине это примерно в 4 раза быстрее, чем принятый ответ, а от 6,6 до 7 раз медленнее, чем @ virgo47 (принятый ответ примерно на 26 раз медленнее, чем @ virgo47 на моей машине).
С 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». Это хороший пример ограничений подхода «стриптиз-акцентов».
В зависимости от языка эти могут не считаться акцентами (которые изменяют звук буквы), но диакритические метки
https://en.wikipedia.org/wiki/Diacritic #Languages_with_letters_containing_diacritics
«Боснийский и хорватский имеют символы č, ć, đ, š и ž, которые считаются отдельными буквами и перечислены как таковые в словарях и других контекстах, в которых указаны слова в соответствии с алфавитным порядком ».
Удаление их может по своей сути изменить значение слова или изменить буквы на совершенно разные.
System.out.println(Normalizer.normalize("àèé", Normalizer.Form.NFD).replaceAll("\\p{InCombiningDiacriticalMarks}+", ""));
работал для меня. Вывод фрагмента выше дает «aee», который я хотел, но
System.out.println(Normalizer.normalize("àèé", Normalizer.Form.NFD).replaceAll("[^\\p{ASCII}]", ""));
не выполнял никакой замены.
Я предлагаю 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);
}
EDIT: Если вы не застряли с Java & lt; 6, и скорость не является критичной, и / или таблица перевода слишком ограничена, используйте ответ Дэвида. Дело в том, чтобы использовать 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);
}
Тесты на моем HW с 32-битный JDK показывает, что он выполняет преобразование из aeelstc89FDČ в aeelstc89FDC 1 миллион раз в ~ 100 мс, в то время как способ Normalizer делает его в 3.7s (37x медленнее).
Наслаждайтесь: -)
Наслаждайтесь: -) Наслаждайтесь: -)Я столкнулся с той же проблемой, связанной с проверкой равенства строк. Одна из строк сравнения имеет код символа ASCII 128-255 .
, т. е. неразрывная space - [Hex - A0] Space [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,
blockquote>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(); }
- ➩ ASCII транслитерации Строка Unicode для Java.
unidecode
String initials = Unidecode.decode( s2 );
- ➩ с помощью
Guava
: Google CoreLibraries for Java
.Для URL-кодирования для пробела используйте Guava laibrary.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, которые описаны в стандартном приложении Unicode № 15 - формах нормализации Unicode и два метода доступа к ним.
s2 = Normalizer.normalize(s2, Normalizer.Form.NFKC);
Тестирование Строки и выходы на разных подходах, таких как ➩ 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"); } }