Как удалить символы акцента из InputStream

Я пытаюсь проанализировать канал Rss2.0 на Android с помощью синтаксического анализатора Pull.

XmlPullParser parser = Xml.newPullParser();
parser.setInput(url.open(), null);

В прологе XML-канала указано, что используется кодировка "utf-8". Когда я открываю удаленный поток и передаю его моему синтаксическому анализатору, я получаю недопустимый токен, документирую неправильно сформированные исключения.

Когда я сохраняю XML-файл и открываю его в браузере (FireFox), браузер сообщает о наличии в файле символа Unicode 0x12 (серьезный акцент?) и не может отображать XML.

Каков наилучший способ обработки таких случаев, предполагая, что у меня нет никакого контроля над возвращаемым XML?

Спасибо.


person Samuh    schedule 18.05.2010    source источник


Ответы (5)


Где вы нашли, что 0x12 - это серьезный ударение? UTF-8 имеет диапазон символов 0x00-0x7F, закодированный так же, как ASCII, а кодовая точка ASCII 0x12 является управляющим символом, DC2 или CTRL+R.

Похоже на какую-то проблему с кодировкой. Самый простой способ решить эту проблему — просмотреть файл, который вы сохранили, в шестнадцатеричном редакторе. Есть несколько вещей, которые нужно проверить:

  1. метка порядка байтов (BOM) в начале может сбить с толку некоторые анализаторы XML.
  2. даже несмотря на то, что в объявлении XML указано, что кодировка находится в UTF-8, на самом деле она может не иметь этой кодировки, и файл будет декодирован неправильно.
  3. не все символы Юникода допустимы в XML, поэтому Firefox отказывается их отображать. В частности, спецификация XML говорит, что 0x9, 0xA и 0xD являются единственными допустимыми символами меньше, чем 0x20, поэтому 0x12 определенно вызовет ворчание соответствующих парсеров.

Если вы можете загрузить файл в pastebin или аналогичный, я могу помочь найти причину и предложить решение.

EDIT: Хорошо, вы не можете загрузить. Это понятно.

XML, который вы получаете, каким-то образом поврежден, и идеальный способ действий — связаться со стороной, ответственной за его создание, чтобы узнать, можно ли решить проблему.

Прежде чем сделать это, нужно проверить одну вещь: вы уверены, что получаете данные в целости и сохранности? Некоторые формы связи (SMS) разрешают использовать только 7-битные символы. Это превратит 0x92 (прямой тик/апостроф ASCII - серьезный ударение?) в 0x12. Похоже на совпадение, особенно если они появляются в файле, где вы ожидаете акцент.

В противном случае вам придется постараться максимально использовать то, что у вас есть:

  1. хотя это и не обязательно, будьте осторожны и передайте «UTF-8» в качестве второго параметра для setInput в синтаксическом анализаторе.

  2. аналогичным образом заставьте синтаксический анализатор использовать другую кодировку символов, передав другую кодировку в качестве второго параметра. Кодировки, которые можно попробовать в дополнение к «UTF-8», — это «iso-8859-1» и «UTF-16». Полный список поддерживаемых кодировок для java приведен на странице Sun site – вы можете попробовать все это. (Я не смог найти полный список поддерживаемых кодировок для Android.)

  3. В крайнем случае вы можете удалить недопустимые символы, например. удалите все символы ниже 0x20, которые не являются пробелами (0x9,0xA и 0xD - все пробелы). Если удалить их сложно, вы можете вместо этого заменить их.

Например

class ReplacingInputStream extends FilterInputStream
{
   public int read() throws IOException
   {
      int read = super.read();
      if (read!=-1 && read<0x20 && !(read==0x9 || read==0xA || read==0xB))
         read = 0x20;
      return read;          
   }
}

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

person mdma    schedule 24.05.2010
comment
Я пробовал 1 и 2 без особой удачи; Третий вариант - единственный оставшийся, и я, скорее всего, выберу его. Спасибо за ваше терпение и помощь с этим .. ура! - person Samuh; 31.05.2010
comment
Вы видели комментарий о SMS и 7-битных символах? Возможно, стоит попросить источник отправить вам XML по другому маршруту, чтобы подтвердить, что то, что вы загрузили, совпадает с оригиналом. - person mdma; 31.05.2010
comment
Разве в примере не должно быть 0xD вместо 0xB - person saurabheights; 22.01.2015

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

Попробуйте вставить содержимое тегов в эти теги

Как это

<title>My title</title>
<link>http://mylink.com</link>
<description>My description</description>

К этому

<title><![CDATA[My title]]></title>
<link><![CDATA[http://milynk.com]]></link>
<description><![CDATA[My Description]]></description>

Регулярное выражение не должно быть очень сложным для понимания. Это работает для меня, надеюсь, что это поможет вам.

person Erik Escobedo    schedule 24.05.2010
comment
Кстати, я нашел регулярное выражение, используемое нашей системой: string.gsub /‹link›(.*)‹/link›/, '‹link›‹![CDATA[\1]]‹/link›' Эта функция для Rails, но регулярное выражение одинаково для всех языков. - person Erik Escobedo; 31.05.2010

Проблема с UTF-8 в том, что это многобайтовая кодировка. Таким образом, ему нужен способ указать, когда символ состоит из более чем одного байта (возможно, двух, трех, четырех,...). Это можно сделать, зарезервировав некоторые значения байтов для обозначения многобайтовых символов. Таким образом, кодирование следует некоторым основным правилам:

  • Однобайтовые символы не имеют набора MSB (коды, совместимые с 7-битным ASCII).
  • Двухбайтовые символы представлены последовательностью: 110xxxxx 10xxxxxx
  • Три байта: 1110xxxx 10xxxxxx 10xxxxxx
  • Четыре байта: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

Ваша проблема заключается в том, что вы можете читать некоторую строку символов, предположительно закодированную как UTF-8 (как указано в определении кодировки XML), но фрагмент байта может не быть действительно закодирован в UTF-8 (это распространенный ошибка объявлять что-то как UTF-8, но кодировать текст с другой кодировкой, такой как Cp1252). Ваш анализатор XML пытается интерпретировать фрагменты байтов как символы UTF-8, но находит что-то, что не соответствует правилам кодирования (недопустимый символ). т.е. два байта с двумя старшими установленными байтами вызовут недопустимую ошибку кодирования: за 110xxxxx всегда должно следовать 10xxxxxx (такие значения, как 01xxxxxx 11xxxxxx 00xxxxxx, будут недопустимыми).

Эта проблема не возникает, когда используются кодировки с непеременной длиной. т.е. если вы указываете в своей декларации XML, что ваш файл использует кодировку Windows-1252, но в конечном итоге вы используете ANSI, ваша единственная проблема будет заключаться в том, что символы, отличные от ASCII (значения> 127), будут отображаться неправильно.


Решение:

  1. Try to detect encoding by other means.
    • If you will always be reading data from same source you could sample some files and use an advanced text editor that tries to infer actual encoding of the file (i.e. notepad++, jEdit, etc.).
    • Делайте это программно. Предварительно обработайте необработанные байты перед выполнением какой-либо фактической обработки xml.
  2. Принудительно фактическое кодирование в процессоре XML

В качестве альтернативы, если вы не возражаете против символов, отличных от ASCII (независимо от того, появляются ли странные символы время от времени), вы можете сразу перейти к шагу 2 и принудительно использовать для обработки XML любую совместимую с ASCII 8-байтовую кодировку фиксированной длины. (ANSI, любая кодировка Windows-XXXX, кодировка Mac-Roman и т. д.). С вашим нынешним кодом вы просто можете попробовать:

XmlPullParser parser = Xml.newPullParser();
parser.setInput(url.open(), "ISO-8859-1");
person Fernando Miguélez    schedule 27.05.2010

Вызов setInput(istream, null) уже означает, что парсер pull пытается определить кодировку самостоятельно. Это явно не удается из-за фактической проблемы с файлом. Так что это не значит, что ваш код неправильный - нельзя ожидать, что вы сможете проанализировать все неправильные документы, будь то неправильно сформированные или с неправильными кодировками.

Однако, если вы обязательно пытаетесь проанализировать этот конкретный документ, вы можете изменить свой код синтаксического анализа, чтобы он находился в функции, которая принимает кодировку в качестве параметра и заключена в блок try/catch. В первый раз не указывайте кодировку, и если вы получите ошибку кодировки, перезапустите ее с ISO-8859-1. Если это обязательно для успеха, повторите для других кодировок, в противном случае вызов завершается после двух.

person JRL    schedule 28.05.2010

Перед синтаксическим анализом вашего XML вы можете настроить его и вручную удалить диакритические знаки перед его синтаксическим анализом. Возможно, пока это не лучшее решение, но со своей задачей оно справится.

person MounirReg    schedule 18.05.2010
comment
бросить их? Мне придется использовать регулярное выражение или, возможно, сканировать ответ для каждого символа. надеюсь до этого не дойдет! - person Samuh; 18.05.2010