2010-01-19 3 views
8

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

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

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

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

+5

Что вы намерены преобразовать 口水 雞 в? Я не знаю, как можно выразить концепцию курицы слюны в трех символах ascii. – novalis

+0

Неясно - пытаетесь ли вы сохранить количество символов или количество байтов ... или, возможно, ширину строки при отображении? – MtnViewMark

+0

@novalis +1 для курицы слюны :-) –

ответ

12

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

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 

Таким образом, вы сначала удалить diactrical знаки, обращенный к ASCii. Символы без знаков ascii станут вопросительными знаками.

+0

Спасибо ... кажется, работает почти нормально. Но есть проблема с символом '^'. Когда он находится внутри строки (например, «he ^^ o»), она терпит неудачу (просто удаляется). – Zardoz

+0

Просто удалите \\ p {IsLm} \\ p {IsSk} из регулярного выражения. –

+1

Если кто-то хочет убрать знаки вопроса и полностью уменьшить текст основных букв попробовать: «[\\ P {InBasicLatin}] +» (обратите внимание на верхний регистр P означает «Не в) Испытано с помощью:. Rrrr̈r'ŕřttẗţỳỹẙy'yýÿŷpp̈sss̈s̊s's̸śŝŞşšddd̈ďd'ḑf̈f̸ggg̈g'ģq ĝǧḧĥj̈j'ḱkk̈k̸ǩlll̈Łłẅẍcc̈c̊c'c̸Çççćĉčvv̈v'v̸bb̧ǹnn̈n̊n'ńņňñmmmm̈ m̊m̌ǵß – RedYeti

7

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

+0

Возможно, это именно то, что Zardoz действительно хотел, хотя он будет неэффективным для персонажей, которых нет на латинских страницах. –

+0

+1 это похоже на лучшее решение проблемы (насколько можно сказать из вопроса). –

+0

Нормировка Юникода будет работать только для символов, которые могут состоять из простого латинского символа из кодировки ASCII и метки диакритики. – jarnbjo

2

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

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

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

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

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

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

+0

Java использует UTF-16 для строк внутри, поэтому для наиболее распространенных «западных» языков исходный текст и текст с уменьшенной ASCII будут иметь одинаковую длину (сохраняйте случайную нечетную пунктуацию). –

2

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

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

2

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

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

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

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

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