Замена символа пресечения юникода на ASCII-аппроксимации
Я читаю некоторые текстовые файлы в программе Java и хотел бы заменить некоторые символы Unicode на ASCII-приближения. Эти файлы в конечном итоге будут разбиты на предложения, которые подаются в OpenNLP. OpenNLP не распознает символы Юникода и дает неправильные результаты по ряду символов (он символизирует «девушку» как «девушка» и «с», но если это котировка Юникода, она рассматривается как один токен).
Например, исходное предложение может содержать направленную котировку Unicode U2018 (‘), и я хотел бы преобразовать ее в U0027 (‘). В конце концов я удалю оставшийся Unicode.
Я понимаю, что теряю информацию, и я знаю, что могу писать регулярные выражения для преобразования каждого из этих символов, но я спрашиваю, есть ли код, который я могу повторно использовать, чтобы преобразовать некоторые из этих символов.
- Может ли GNU sed (для Windows) обрабатывать Unicode? Если да, то это проблема с кодовой страницей / языковой версией или с коммутатором?
- Почему длина этой строки больше, чем количество символов в ней?
- Анализ текста на арабском / RTL слева направо
- Вход Unicode, полученный через входные компоненты PrimeFaces, поврежден
- Как я должен подготовить свои 32-разрядные программы Delphi для возможного 64-битного компилятора?
Это то, что я мог, но я уверен, что буду совершать ошибки / пропустить вещи / etc .:
// double quotation (") replacements.add(new Replacement(Pattern.compile("[\u201c\u201d\u201e\u201f\u275d\u275e]"), "\"")); // single quotation (') replacements.add(new Replacement(Pattern.compile("[\u2018\u2019\u201a\u201b\u275b\u275c]"), "'"));
замены – это особый class, который я позже запускаю и применяю замены.
for (Replacement replacement : replacements) { text = replacement.pattern.matcher(text).replaceAll(r.replacement); }
Как вы можете видеть, мне пришлось найти:
- ЛЕВАЯ ОДНОМЕСТНАЯ ЦЕНА
- ПРАВИЛЬНАЯ ОДНОЦВЕТНАЯ МАРКА
- SINGLE LOW-9 QUOTATION MARK (что это / следует заменить?)
- ОДИНОЧНАЯ ВЫСОКАЯ-ПЕРЕСМОТРЕННАЯ-9 ЦИТАТА (что это / следует заменить?)
- Как преобразовать символ Unicode в его эквивалент ASCII
- Некоторые юникодовые альт-коды не работают
- Обработка Юникода в C ++
- Символ новой строки Unicode (\ u000d) в Java
- Преобразование Unicode в ASCII без ошибок в Python
- Windows 7 UTF-8 и Unicode
- Проблемы с символами UTF-8; я не вижу того, что я хранил
- Почему по умолчанию stream файлов в C ++ имеет узкие письменные данные?
Каждому символу юникода присваивается категория . Для кавычек существует две отдельные категории:
- Пунктуация, Окончательная цитата (может вести себя как Ps или Pe в зависимости от использования)
- Пунктуация, Начальная цитата (может вести себя как Ps или Pe в зависимости от использования)
С этими списками вы должны иметь возможность обрабатывать все кавычки соответствующим образом, если вы хотите закодировать регулярное выражение вручную.
Java Character.getType дает вам категорию символов, например FINAL_QUOTE_PUNCTUATION
.
Теперь вы можете получить категорию каждого (символ пунктуации) и заменить ее соответствующим дополнением в ASCII.
Вы можете использовать другие знаки препинания. В «Пунктуация, другое» есть некоторые символы, например PRIME ′
, которые вы также можете заменить апострофом.
Я нашел довольно обширную таблицу, которая отображает пунктуацию Unicode в их ближайших эквивалентах ASCII .
Вот еще информация: Символы карты и знаки препинания для ASCII .
Я следил за ссылкой @ marek-stoj и создал приложение Scala, которое очищает unicode от строк при сохранении длины строки. Он удаляет диакритические знаки (акценты) и использует карту, предложенную @ marek-stoj, для преобразования символов Unicode без Ascii в их приближения ascii.
import java.text.Normalizer object Asciifier { def apply(string: String) = { var cleaned = string for ((unicode, ascii) <- substitutions) { cleaned = cleaned.replaceAll(unicode, ascii) } // convert diacritics to a two-character form (NFD) // http://docs.oracle.com/javase/tutorial/i18n/text/normalizerapi.html cleaned = Normalizer.normalize(cleaned, Normalizer.Form.NFD) // remove all characters that combine with the previous character // to form a diacritic. Also remove control characters. // http://docs.oracle.com/javase/6/docs/api/java/util/regex/Pattern.html cleaned.replaceAll("[\\p{InCombiningDiacriticalMarks}\\p{Cntrl}]", "") // size must not change require(cleaned.size == string.size) cleaned } val substitutions = Set( (0x00AB, '"'), (0x00AD, '-'), (0x00B4, '\''), (0x00BB, '"'), (0x00F7, '/'), (0x01C0, '|'), (0x01C3, '!'), (0x02B9, '\''), (0x02BA, '"'), (0x02BC, '\''), (0x02C4, '^'), (0x02C6, '^'), (0x02C8, '\''), (0x02CB, '`'), (0x02CD, '_'), (0x02DC, '~'), (0x0300, '`'), (0x0301, '\''), (0x0302, '^'), (0x0303, '~'), (0x030B, '"'), (0x030E, '"'), (0x0331, '_'), (0x0332, '_'), (0x0338, '/'), (0x0589, ':'), (0x05C0, '|'), (0x05C3, ':'), (0x066A, '%'), (0x066D, '*'), (0x200B, ' '), (0x2010, '-'), (0x2011, '-'), (0x2012, '-'), (0x2013, '-'), (0x2014, '-'), (0x2015, '-'), (0x2016, '|'), (0x2017, '_'), (0x2018, '\''), (0x2019, '\''), (0x201A, ','), (0x201B, '\''), (0x201C, '"'), (0x201D, '"'), (0x201E, '"'), (0x201F, '"'), (0x2032, '\''), (0x2033, '"'), (0x2034, '\''), (0x2035, '`'), (0x2036, '"'), (0x2037, '\''), (0x2038, '^'), (0x2039, '<'), (0x203A, '>'), (0x203D, '?'), (0x2044, '/'), (0x204E, '*'), (0x2052, '%'), (0x2053, '~'), (0x2060, ' '), (0x20E5, '\\'), (0x2212, '-'), (0x2215, '/'), (0x2216, '\\'), (0x2217, '*'), (0x2223, '|'), (0x2236, ':'), (0x223C, '~'), (0x2264, '<'), (0x2265, '>'), (0x2266, '<'), (0x2267, '>'), (0x2303, '^'), (0x2329, '<'), (0x232A, '>'), (0x266F, '#'), (0x2731, '*'), (0x2758, '|'), (0x2762, '!'), (0x27E6, '['), (0x27E8, '<'), (0x27E9, '>'), (0x2983, '{'), (0x2984, '}'), (0x3003, '"'), (0x3008, '<'), (0x3009, '>'), (0x301B, ']'), (0x301C, '~'), (0x301D, '"'), (0x301E, '"'), (0xFEFF, ' ')).map { case (unicode, ascii) => (unicode.toChar.toString, ascii.toString) } }
Хотя это точно не отвечает на ваш вопрос, вы можете преобразовать текст в Unicode в US-ASCII, заменяя символы, отличные от ASCII, на «?» символы.
String input = "aáeéiíoóuú"; // 10 chars. Charset ch = Charset.forName("US-ASCII"); CharsetEncoder enc = ch.newEncoder(); enc.onUnmappableCharacter(CodingErrorAction.REPLACE); enc.replaceWith(new byte[]{'?'}); ByteBuffer out = null; try { out = enc.encode(CharBuffer.wrap(input)); } catch (CharacterCodingException e) { /* ignored, shouldn't happen */ } String outStr = ch.decode(out).toString(); // Prints "a?e?i?o?u?" System.out.println(outStr);
То, что я сделал для подобных подстановок, – это создать Map
(обычно HashMap
) с символами Unicode в качестве ключей и их заменять значениями.
Псевдо-Java; for
зависит от того, какой контейнер символов вы используете в качестве параметра для метода, который делает это, например String, CharSequence и т. д.
StringBuilder output = new StringBuilder(); for (each Character 'c' in inputString) { Character replacement = xlateMap.get( c ); output.append( replacement != null ? replacement : c ); } return output.toString();
Все, что находится на Карте, заменено, все, что не на карте, не изменяется и копируется для вывода.
Вот пакет Python, который делает хорошую работу. Он основан на модуле Perl Text :: Unidecode. Я предполагаю, что это можно портировать на Java.
http://www.tablix.org/~avian/blog/archives/2009/01/unicode_transliteration_in_python/