Почему stringr меняет кодировку при работе со строками?

Это странное поведение stringr меня очень раздражает. stringr без предупреждения изменяет кодировку некоторых строк, содержащих экзотические символы, в моем случае ø, å, æ, é и некоторые другие... Если вы str_trim вектор символов, то те, что содержат экзотические буквы, будут преобразованы в новый Кодирование.

letter1 <- readline('Gimme an ASCII character!')     # try q or a
letter2 <- readline('Gimme an non-ASCII character!') # try ø or é
Letters <- c(letter1, letter2)
Encoding(Letters)           # 'unknown'
Encoding(str_trim(Letters)) # mixed 'unknown' and 'UTF-8'

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

Любой обходной путь?

РЕДАКТИРОВАТЬ: я думал, что смогу вернуться к базовым функциям, но они не защищают кодировку. paste сохраняет его, но не sub например.

 Encoding(paste(' ', Letters))                 # 'unknown'
 Encoding(str_c(' ', Letters))                 # mixed
 Encoding(sub('^ +', '', paste(' ', Letters))) # mixed

person Arthur    schedule 02.11.2015    source источник
comment
Я вижу, что это смешано и для letters. Кстати, letters — это константная строка в базе R.   -  person Frank    schedule 02.11.2015
comment
«неизвестно» - это локальная кодировка, если я правильно понял, так что это может зависеть от машин, я думаю ... Я изменил буквы на буквы, так как вы казались раздраженными, я перезаписываю константу.   -  person Arthur    schedule 02.11.2015
comment
Если у вас есть способ создать «неизвестную» кодировку на любой машине, поделитесь, пожалуйста!   -  person Arthur    schedule 02.11.2015
comment
Вы можете сделать Encoding(Letters) = '', чтобы очистить кодировку. Но это не очень удовлетворительное решение.   -  person Konrad Rudolph    schedule 02.11.2015
comment
Кажется, что это работает, но я не уверен, что это работает все время. Я думаю, что у меня были ситуации, когда функция Encoding<- не меняла фактическую кодировку. Но не могу найти ни одного примера прямо сейчас.   -  person Arthur    schedule 02.11.2015
comment
Я не специалист по кодировкам, я просто говорю, что на моей машине: Encoding(c("a","ø")) # [1] "unknown" "latin1" в отличие от неизвестного на вашей. Меня не раздражают ваши имена переменных :), просто сообщаю вам об этом.   -  person Frank    schedule 02.11.2015
comment
Понятно. И я знал о letters, но letters не содержит никаких экзотических символов.   -  person Arthur    schedule 02.11.2015
comment
@KonradRudolph Можете ли вы поместить это в качестве ответа, пока он работает, даже если не удаляет вопрос о том, почему функции манипулирования строками действительно меняют кодировку ...   -  person Arthur    schedule 06.11.2015


Ответы (3)


R не всегда упрощает преобразование между кодировками (есть функция iconv для этого, но то, что принимает эта функция, зависит от платформы). Однако, по крайней мере, вы всегда можете сбросить маркировку кодировки строки на «неизвестно»:

Letters = str_trim(Letters)
Encoding(Letters)
# [1] "unknown" "UTF-8"
Encoding(Letters) = ''
Encoding(Letters)
# [1] "unknown" "unknown"

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

Encoding иллюстрирует проблемы R с правильной работой с кодировками. В документации говорится:

Строки ASCII никогда не будут отмечены объявленной кодировкой, поскольку их представление одинаково во всех поддерживаемых кодировках.

… что, очевидно, совершенно бесполезно (а также более чем немного вводит в заблуждение; строка UTF-8, состоящая только из кодовых точек ‹ 128, может выглядеть неотличимой от строки ASCII, но работа с ней должна давать разные результаты в зависимости от кодировки, которая почему это должно эффективно помечаться).

Интересно, что ни enc2native, ни enc2utf8 не сделают здесь желаемого — оба будут давать разные кодировки для двух строк в Letters, что является прямым следствием упомянутой выше проблемы Encoding.

person Konrad Rudolph    schedule 06.11.2015
comment
Подход, предложенный в этом ответе, не является хорошим. Во-первых, это вообще не будет работать в Windows (или, возможно, на любой платформе, где кодировка по умолчанию не UTF8). Во-вторых, нет четкого различия между изменением кодировки (например, с помощью iconv) и отметкой кодировки (с помощью Encoding). В более общем смысле проблема, которую он пытается решить, на самом деле не существует; строки, возвращаемые str_trim и другими функциями в пакете stringr, в полном порядке, а элементы не имеют разных кодировок. Как задокументировано, Encoding не отмечает символы ascii. - person Ista; 07.11.2015
comment
@Ista Вы говорите, что разные кодировки не представляют проблемы, но если вы посмотрите на вопрос, это просто неправда. Кроме того, я намеренно отмечаю только кодировку, а не преобразование, поскольку, как вы заметили, преобразование кодировки в R не поддерживается в одинаковой степени на всех платформах. Теперь я полностью согласен с вами в том, что это не правильное решение, поэтому я опубликовал именно это как контент, а не ответ, пока ОП не попросил меня также опубликовать ответ. - person Konrad Rudolph; 07.11.2015
comment
Не существует разных кодировок. Все элементы вектора символов, возвращаемые str_trim, кодируются в UTF-8. Попробуйте запустить этот ответ в Windows (после этого напечатайте Letters), и вы поймете, почему удаление маркера кодировки — плохая идея. Попробуйте на самом деле объединить некоторые объекты data.table в кодированные строки UTF-8 (не удаляя Encoding), и вы увидите, что это работает правильно, как и говорится в предупреждающем сообщении. Я знаю, почему вы опубликовали этот ответ, но ради того, чтобы другие сталкивались с этим вопросом в будущем, отредактируйте, чтобы было ясно, что это вызывает проблемы. - person Ista; 07.11.2015
comment
@Ista Итак, вы говорите, что вопреки тому, что сказал ОП, data.table принимает это? Ну, в таком случае этот ответ явно бесполезен. - person Konrad Rudolph; 08.11.2015
comment
merge.data.table выдает предупреждение, но сливается корректно. Текст предупреждения указывает на то, что в обсуждаемых здесь условиях проблем нет. - person Ista; 08.11.2015
comment
@Ista Вздох. Спасибо, я изменю ответ позже. - person Konrad Rudolph; 08.11.2015
comment
Есть ли шанс, что поведение ASCII будет изменено в R? Благодаря вашему ответу я понял свою проблему здесь, но если мне кажется, что я начну с взлома... - person Christoph; 11.07.2017

stringr меняет кодировку, потому что stringr является оболочкой пакета stringi, а stringi всегда кодирует в UTF-8. См. help("stringi-encoding", package = "stringi") для получения подробной информации и объяснения этого выбора конструкции.

Чтобы избежать проблем с объединением data.table, просто убедитесь, что все переменные id закодированы в UTF-8. Вы можете сделать это, используя stri_enc_toutf8 в пакете stringi или используя iconv.

person Ista    schedule 03.11.2015
comment
использование iconv дает явно смешанную кодировку: Encoding(iconv(Letters, to='UTF-8')); stri_enc_toutf8 неожиданно дает единообразно закодированный вектор...: Encoding(stringi:::stri_enc_toutf8(Letters)) ; чего я не понимаю, так это почему смешанное кодирование? - person Arthur; 04.11.2015
comment
Вероятно, это не совсем смешанное, это просто особенность функции Encoding. В частности, символы ASCII никогда не помечаются кодировкой, подробности см. в разделе ?Encoding. - person Ista; 04.11.2015
comment
Спасибо за объяснение. Но тогда, если смешанное кодирование используется по умолчанию, почему data.table жалуется на это? И почему он так плохо с этим справляется? За исключением нескольких сотен миллионов англоязычных, все остальные используют символы, отличные от ASCII. Я имею в виду: нежелательным последствием использования функций stringr является то, что я получаю UTF-8 для символов, отличных от ASCII; но я получаю неверные результаты в data.frame при слиянии с ними. - person Arthur; 04.11.2015
comment
@ Артур Я думаю, что предупреждение merge.data.table довольно ясно. Как объяснено там, слияние должно быть выполнено правильно, если единственными неотмеченными символами являются ASCII. Если это не так, вы должны открыть отчет об ошибке для data.table или, по крайней мере, опубликовать вопрос SO, который включает воспроизводимый пример ошибок слияния data.table, которые вы видите. - person Ista; 04.11.2015
comment
Полностью согласен. Я не обвиняю data.table, который работает по назначению. Однако, если я использую функции манипулирования строками на лету внутри data.table, я получаю неправильные слияния без предупреждения, так как я получаю 2 кодировки без предупреждения: локальную и UTF-8. - person Arthur; 06.11.2015
comment
@ Артур Нет, ты невнимательно прочитал мой комментарий. Вы не должны не получать неправильные слияния. Если вы это сделаете, вам следует задать вопрос об этом здесь, на SO, или открыть отчет об ошибке. - person Ista; 06.11.2015
comment
DT <- data.table(letters=sample(c('a', 'ø'), 10, TRUE) %>% `Encoding<-`(''), numbers=1:10); DT2 <- DT[,list(.N), keyby=list(letters2=str_replace(letters, 'ø', 'å'))]['å' %>% `Encoding<-`('')]; Encoding(DT2$letters2) вроде работает. Если я найду пример, я вернусь. - person Arthur; 06.11.2015

Благодаря этой недавней фиксации data.table теперь неявно заботится об этих смешанных кодировках, обеспечение правильной кодировки при создании data.tables, а также обеспечение правильной кодировки в таких функциях, как unique() и duplicated().

См. новость (23) в разделе об ошибках для v1.9.7 в README.md< /а>.

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

person Arun    schedule 20.01.2016