Конвертировать Unicode в ASCII без изменения длины строки (в Java) - PullRequest
9 голосов
/ 19 января 2010

Каков наилучший способ преобразовать строку из Unicode в ASCII без изменения ее длины (это очень важно в моем случае)?Также символы без каких-либо проблем преобразования должны быть в тех же позициях, что и в исходной строке.Таким образом, «Ä» должен быть преобразован в «A», а не что-то загадочное, имеющее больше символов.

Редактировать:
@novalis - Такие символы (например, азиатские языки) следует просто преобразовать в некоторыезаполнители.Меня не слишком интересуют эти слова или их значение.

@ MtnViewMark - я должен сохранять количество всех символов и положение доступных символов ASCII при любых обстоятельствах.

Вот еще некоторыеинформация: у меня есть несколько инструментов для интеллектуального анализа текста, которые могут обрабатывать только строки ASCII.Большая часть текста, который должен быть обработан, написана на английском языке, но некоторые содержат не символы ASCII.Меня не интересуют эти слова, но я должен быть уверен, что слова, которые меня интересуют (те, которые содержат только символы ASCII), находятся на тех же позициях после преобразования строки.

Ответы [ 5 ]

14 голосов
/ 20 января 2010

Как указано в этом ответе, следующий код должен работать:

    String s = "口水雞 hello Ä";

    String s1 = Normalizer.normalize(s, Normalizer.Form.NFKD);
    String regex = "[\\p{InCombiningDiacriticalMarks}\\p{IsLm}\\p{IsSk}]+";

    String s2 = new String(s1.replaceAll(regex, "").getBytes("ascii"), "ascii");

    System.out.println(s2);
    System.out.println(s.length() == s2.length());

Вывод

??? hello A
true

Итак, вы сначала удалите диалектические меткив ascii.Символы, отличные от ascii, станут знаками вопроса.

8 голосов
/ 19 января 2010

Используйте java.text.Normalizer.normalize() с Normalizer.Form.NFD, затем отфильтруйте символы не ASCII.

2 голосов
/ 23 ноября 2012

Как отметил Пол Тейлор: есть проблема с использованием Normalizer, если вам нужно, чтобы проект был компилируемым / запускаемым в pre-1.6, а также в 1.6 и выше java.У вас возникнут проблемы, поскольку Normalizer находится в разных пакетах (java.text.Normalizer (для 1.6) вместо sun.text.Normalizer (для до 1.6)) и имеет другой метод-подпись.

Обычно рекомендуется использоватьотражение, чтобы вызвать соответствующий метод Normalizer.normalize ().( Пример можно найти здесь ).Но если вы не хотите добавлять в свой код отражение, вы можете использовать icu4j library .Он содержит класс com.ibm.icu.text.Normalizer с методом normalize(), который выполняет ту же работу, что и java.text.Normalizer / sun.text.Normalizer.Библиотека Icu имеет (должна иметь) собственную реализацию Normalizer, чтобы вы могли поделиться своим проектом с библиотекой, и это должно быть независимым от Java. Недостаток в том, что библиотека icu довольно большая.

Если вы используете класс Normalizer только для удаления акцентов / диакритических знаков из строк, есть и другой способ.Вы можете использовать библиотеку Apache commons lang (версия 3) , которая содержит StringUtils с методом stripAccents():

String noAccentsString = org.apache.commons.lang3.StringUtils.stripAccents(s);

Библиотека Lang3, вероятно, использует отражение для вызова соответствующего нормализатора в соответствии с Javaверсия.Преимущество в том, что в вашем коде нет проблем с отражением.

2 голосов
/ 03 июня 2010

Одна проблема с Normalizer состоит в том, что до Java 1.6 он был в пакете sun.text, тогда как в 1.6 он был в пакете java.text и его сигнатура метода изменилась. Поэтому, если ваше приложение необходимо запустить на обеих платформах, вам придется использовать рефлексию.

Альтернативное пользовательское решение описывается как techniwue 3 здесь

2 голосов
/ 19 января 2010

Предостережение: я не знаю Java. Немного о наборе символов.

Вы не указываете, какой набор символов вы используете точно.

Но независимо от того, что вы используете, невозможно преобразовать строку Unicode в ASCII и сохранить исходную длину и положение символов, просто потому что набор символов Unicode будет использовать несколько байтов для некоторых персонажей (очевидно).

Единственное исключение, о котором я знаю, это строка UTF-8, содержащая только символы ASCII: эта строка уже будет идентична как в UTF-8, так и в ASCII, поскольку UTF-8 использует многобайтовые символы только при необходимости. (Я не знаю о других разновидностях Unicode, могут быть и другие динамические).

Единственный обходной путь, который я вижу, - это добавление пробела к любому специальному символу, который был заменен на ASCII, но это испортит строку (Göteborg в UTF8 должен был бы стать Go teborg, чтобы сохранить длину) .

Может быть, вы хотите уточнить, чего вы хотите / нужно достичь, чтобы люди здесь могли предложить обходные пути.

...