Чтение текстового файла в кодировке UTF-8 в Mathematica

Как я могу прочитать текстовый файл с кодировкой utf-8 в Mathematica?

Это то, что я делаю сейчас:

text = Import["charData.txt", "Text", CharacterEncoding -> "UTF8"];

но это говорит мне, что

$CharacterEncoding::utf8: "The byte sequence {240} could not be interpreted as a character in the UTF-8 character encoding"

и так далее. Я не уверен почему. Я считаю, что файл действителен UTF-8.

Вот файл, который я пытаюсь прочитать:

http://dl.dropbox.com/u/38623/charData.txt

1 ответ

Короткая версия: функция Mathematica UTF-8 не работает для кодов символов с более чем 16 битами. Вместо этого используйте кодировку UTF-16, если это возможно. Но имейте в виду, что обработка Mathematica 17+ битовых кодов символов, как правило, ошибочна. Длинная версия следует...

Как отмечали многочисленные комментаторы, проблема, по-видимому, связана с поддержкой Mathematica символов Unicode, чьи коды больше 16 бит. Первый такой символ в цитируемом текстовом файле - U + 20B9B (), который появляется в строке 10.

Некоторые версии интерфейса Mathematica (например, 8.0.1 в 64-битной Windows 7) могут обрабатывать соответствующий символ при непосредственном вводе:

In[1]:= $c="";

Но у нас возникают проблемы, если мы пытаемся создать персонажа из его Unicode:

In[2]:= 134043 // FromCharacterCode

During evaluation of In[2]:= FromCharacterCode::notunicode:
A character code, which should be a non-negative integer less
than 65536, is expected at position 1 in {134043}. >>
Out[2]= FromCharacterCode[134043]

Тогда возникает вопрос: что, по мнению Mathematica, код для этого персонажа?

In[3]:= $c // ToCharacterCode
        BaseForm[%, 16]
        BaseForm[%, 2]

Out[3]= {55362,57243}
Out[4]//BaseForm= {d842, df9b}
Out[5]//BaseForm= {1101100001000010, 1101111110011011}

Вместо одного значения Unicode, как можно было ожидать, мы получаем два кода, которые соответствуют UTF-16 представлению этого символа. Mathematica также может выполнять обратное преобразование:

In[6]:= {55362,57243} // FromCharacterCode

Out[6]= 

Какова же тогда концепция Mathematica относительно кодировки UTF-8 этого символа?

In[7]:= ExportString[$c, "Text", CharacterEncoding -> "UTF8"] // ToCharacterCode
        BaseForm[%, 16]
        BaseForm[%, 2]

Out[7]= {237,161,130,237,190,155}
Out[8]//BaseForm= {ed, a1, 82, ed, be, 9b}
Out[9]//BaseForm= {11101101, 10100001, 10000010, 11101101, 10111110, 10011011}

Внимательный читатель заметит, что это кодировка UTF-8 символа UTF-16. Может Mathematica расшифровать это интересное кодирование?

In[10]:= ImportString[
           ExportString[{237,161,130,237,190,155}, "Byte"]
         , "Text"
         , CharacterEncoding -> "UTF8"
         ]

Out[10]= 

Да, оно может! Но... ну и что?

Как насчет настоящего UTF-8 выражения этого персонажа:

In[11]:= ImportString[
           ExportString[{240, 160, 174, 155}, "Byte"]
         , "Text"
         , CharacterEncoding -> "UTF8"
         ]
Out[11]= $CharacterEncoding::utf8: The byte sequence {240} could not be
interpreted as a character in the UTF-8 character encoding. >>
$CharacterEncoding::utf8: The byte sequence {160} could not be
interpreted as a character in the UTF-8 character encoding. >>
$CharacterEncoding::utf8: The byte sequence {174} could not be
interpreted as a character in the UTF-8 character encoding. >>
General::stop: Further output of $CharacterEncoding::utf8 will be suppressed
during this calculation. >>
ð ®

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

Как насчет UTF-16? UTF-16 отсутствует в списке допустимых кодировок символов, но "Unicode" является. Так как мы уже видели, что Mathematica, похоже, использует UTF-16 в качестве своего собственного формата, давайте рассмотрим его (используя UTF-16 с прямым порядком байтов с меткой порядка байтов):

In[12]:= ImportString[
           ExportString[
             FromDigits[#, 16]& /@ {"fe", "ff", "d8", "42", "df", "9b"}
             , "Byte"
           ]
         , "Text"
         , CharacterEncoding -> "Unicode"
         ]
Out[12]= 

Оно работает. В качестве более полного эксперимента я перекодировал цитированный текстовый файл из вопроса в UTF-16 и успешно импортировал его.

В документации Mathematica по этому вопросу ничего не сказано. Интересно отметить, что упоминание Unicode в Mathematica, похоже, сопровождается предположением, что коды символов содержат 16 битов. См., Например, ссылки на Unicode в необработанных кодировках символов.

Из этого следует сделать вывод, что поддержка Mathematica транскодирования UTF-8 отсутствует / содержит ошибки для кодов длиннее 16 бит. UTF-16, кажущийся внутренний формат Mathematica, похоже, работает правильно. Так что это обходной путь, если вы можете перекодировать ваши файлы, и вы можете согласиться с тем, что результирующие строки будут на самом деле в формате UTF-16, а не в истинных строках Unicode.

постскриптум

Через некоторое время после написания этого ответа я попытался снова открыть блокнот Mathematica, в котором он содержится. Каждое появление проблемного персонажа в блокноте было уничтожено и заменено тарабарщиной. Я предполагаю, что есть еще больше ошибок Unicode, даже в Mathematica 8.0.1;)

Другие вопросы по тегам