Замена юникодной пунктуации в ASCII-аппроксимациях - PullRequest
18 голосов
/ 26 января 2011

Я читаю некоторые текстовые файлы в программе на Java и хотел бы заменить некоторые символы Юникода приближениями ASCII.Эти файлы в конечном итоге будут разбиты на предложения, которые подаются в OpenNLP.OpenNLP не распознает символы Unicode и дает неправильные результаты по ряду символов (он маркирует «girl» как «girl» и «s», но если это Unicode-кавычка, он обрабатывается как один токен) ..

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

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

Это то, что я мог, но я уверен, что я буду делать ошибки / пропустить вещи / и т.д.:

    // 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]"), "'"));

replacements - это пользовательский класс, которыйПозже я перебегаю и применяю замену.

    for (Replacement replacement : replacements) {
         text = replacement.pattern.matcher(text).replaceAll(r.replacement);
    }

Как видите, мне нужно было найти:

  • ОСТАВШЕЕ ОДНОМ ОЦЕНОЧНОЕ ЗАКАЗЧИКОЕ
  • ПРАВИЛЬНО ОДНОКВАЦИОННОЕ ЗАЯВЛЕНИЕMARK
  • ОДНА НИЗКАЯ НИЗКАЯ-9 МАРКА ЦИТАТЫ (что это такое / я должен заменить это?)
  • ОДНА ОДНО ВЫСОКАЯ ОБРАТНАЯ ЛИЦА ЦИТАТА 9 (что это такое / я должен заменить это?)

Ответы [ 6 ]

15 голосов
/ 19 июня 2011
6 голосов
/ 24 июня 2013

Я перешел по ссылке @ marek-stoj и создал приложение Scala, которое очищает Юникод от строк, сохраняя при этом длину строки. Он удаляет диакритические знаки (акценты) и использует карту, предложенную @ marek-stoj, для преобразования не-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) }
}
6 голосов
/ 27 января 2011

Каждому символу Юникода присваивается категория . Существует две отдельные категории для цитат:

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

Java Character.getType дает вам категорию символов, например FINAL_QUOTE_PUNCTUATION.

Теперь вы можете получить категорию каждого (пунктуации) символа и заменить ее соответствующим дополнением в ASCII.

Вы можете использовать другие категории пунктуации соответственно. В «Пунктуация, Прочее» есть некоторые символы, например PRIME , которые вы также можете заменить апострофом.

3 голосов
/ 27 января 2011

Хотя это не совсем отвечает на ваш вопрос, вы можете преобразовать текст 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);
2 голосов
/ 25 июля 2012

Вот пакет Python, который хорошо работает.Он основан на модуле Perl Text :: Unidecode.Я предполагаю, что это может быть перенесено на Java.

http://www.tablix.org/~avian/blog/archives/2009/01/unicode_transliteration_in_python/

http://pypi.python.org/pypi/Unidecode

2 голосов
/ 27 января 2011

То, что я сделал для подобных замен, - это создание 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();

Все на Карте заменено, все, что не на Карте, не изменяется и копируется на выход.

...