2017-01-09 4 views
1

Я работаю с текстом, который содержит смайлики. Мне нужно найти их и заменить их тегами, которые можно проанализировать. Как это сделать?Перевод и картирование смайликов, закодированных как код UTF-8 в тексте

> main$text[[4]] 
[1] "Spread d wrd\xf0\u009f\u0098\u008e" 
> grepl("\xf0", main$text[[4]]) 
[1] FALSE 

Я пробовал выше. Почему это не сработало? Я также пробовал iconv в ASCII, тогда байт-кодирование, которое я получил, можно было искать с помощью grepl.

> abc<-iconv(main$text[[4]], "UTF-8", "ASCII", "byte") 
> abc 
[1] "Spread d wrd<f0><9f><98><8e>" 
> grepl("<f0>", abc) 
[1] TRUE 

Я действительно не понимаю, что я здесь и что произошло. Я также не понимаю, как приведенное преобразование вводило в текст \n символов.

Я также не знал, как их закодировать, как только они будут искупительны. Я нашел список here, но он упал (например, "U+E00E" - <ee><80><8e> не было в списке). Существует ли полный список для такого отображения?

ADDENDUM

После многих проб и ошибок, вот что я понял. Для данных emojis есть два типа кодировок. Один из них имеет вид байтов, который доступен для поиска по grepl("\x9f", ...., useBytes=T), как и main$text[[4]], а другой (main$text[[6]]), который можно найти как символ Юникода без useBytes=T, то есть grepl("\ue00e",....). Даже то, как они отображаются в View() и при вызове на консоли, отличается. Я совершенно смущен относительно того, что здесь происходит.

main$text[[4]] 
[1] "Spread d wrd\xf0\u009f\u0098\u008e" 
main[4,] 
      timestamp fromMe    remoteResource remoteResourceDisplayName type 
b 2014-08-30 02:58:58 FALSE [email protected]    ABC text 
             text date 
b Spread d wrd<f0><U+009F><U+0098><U+008E> 307114 
main$text[[6]] 
[1] "" 
main[6,] 
      timestamp fromMe    remoteResource remoteResourceDisplayName type  text 
b 2014-08-30 02:59:17 FALSE [email protected]   XYZ text <U+E00E> 
    date 
b 307114 
grepl("\ue00e", main$text[[6]]) 
[1] TRUE 
grepl("<U+E00E>", main$text[[6]]) 
[1] FALSE 
grepl("\u009f", main$text[[4]]) 
[1] FALSE 
grepl("\x9f", main$text[[4]]) 
[1] FALSE 
grepl("\x9f", main$text[[4]], fixed=T) 
[1] FALSE 
grepl("\x9f", main$text[[4]], useBytes=T) 
[1] TRUE 

Карты, которые у меня есть, также отличаются. Один для байтов работает хорошо. Но другой не делает, так как я не могу создать "\ue00e", необходимый для поиска. Вот пример другой карты, соответствующей Softbank <U+E238>.

emmm[11] 
[1] "E238" 

ответ

1

Поиск одного байта многобайтовой UTF-8 закодированный символ в работает только если сделано с useBytes = TRUE. Тот факт, что "\xf0" здесь является частью многобайтового символа, скрыт менее совершенной поддержкой Unicode R в Windows (используется в исходном примере, я полагаю). Как сопоставить по байтам:

foo <- "\xf0\x9f\x98\x8e" # U+1F60E SMILING FACE WITH SUNGLASSES 
Encoding(foo) <- "UTF-8" 
grepl("\xf0", foo, useBytes = TRUE) 

Я не вижу много пользы для сопоставления одного байта. Затем поиск целого персонажа будет следующим:

grepl(foo, paste0("Smiley: ", foo, " and more"), useBytes = TRUE) 

Действительные коды ASCII соответствуют целым числам 0-127. Преобразование iconv() в ASCII в примере заменяет любой недопустимый байт 0xYZ (соответствующий целым числам 128-255) с буквальным текстом <yz>, где y и z являются шестнадцатеричными цифрами. Насколько я вижу, он не должен вводить новые строки ("\n").

Использование списка символов, связанного с вопросом, вот пример кода, который выполняет один вид тегов emoji для ввода строк, а именно замену emoji на его (слегка отформатированное) имя.

emoji_table <- read.csv2("https://github.com/today-is-a-good-day/Emoticons/raw/master/emDict.csv", 
         stringsAsFactors = FALSE) 

emoji_names <- emoji_table[, 1] 
text_bytes_to_raw <- function(x) { 
    loc <- gregexpr("\\x", x, fixed = TRUE)[[1]] + 2 
    as.raw(paste0("0x", substring(x, loc, loc + 1))) 
} 
emoji_raw <- lapply(emoji_table[, 3], text_bytes_to_raw) 
emoji_utf8 <- vapply(emoji_raw, rawToChar, "") 
Encoding(emoji_utf8) <- "UTF-8" 

gsub_many <- function(x, patterns, replacements) { 
    stopifnot(length(patterns) == length(replacements)) 
    x2 <- x 
    for (k in seq_along(patterns)) { 
     x2 <- gsub(patterns[k], replacements[k], x2, useBytes = TRUE) 
    } 
    x2 
} 

tag_emojis <- function(x, codes, names) { 
    gsub_many(x, codes, paste0("<", gsub("[[:space:]]+", "_", names), ">")) 
} 

each_tagged <- tag_emojis(emoji_utf8, emoji_utf8, emoji_names) 

all_in_one <- tag_emojis(paste0(emoji_utf8, collapse = ""), 
         emoji_utf8, emoji_names) 

stopifnot(identical(paste0(each_tagged, collapse = ""), all_in_one)) 

Как почему U+E00E не в этом списке Emoji, я не думаю, что это должно быть. Эта кодовая точка находится в Private Use Area, где символьные сопоставления не стандартизированы. Для полных списков символов Unicode вы не можете найти более высокий авторитет, чем Консорциум Unicode, например. Unicode Emoji. Дополнительно см. convert utf8 code point strings like <U+0161> to utf8.

Edit после добавления

Когда есть строка ровно четыре шестнадцатеричных цифры, представляющей точку коды Unicode (скажу "E238"), следующий код преобразует строку в соответствующем UTF-8 представительство, появление которых можно проверить с помощью семейства функций grep(). Это отвечает на вопрос о том, как «автоматически» генерировать символ, который можно создать вручную, набрав "\uE238".

library(stringi) 

hex4_to_utf8 <- function(x) { 
    stopifnot(grepl("^[[:xdigit:]]{4}$", x)) 
    stringi::stri_enc_toutf8(stringi::stri_unescape_unicode(paste0("\\u", x))) 
} 

foo <- "E238" 
foo_utf8 <- hex4_to_utf8(foo) 

Значение опции useBytes не имеет значения в следующем grep() вызова. В предыдущем примере кода я использовал useBytes = TRUE в качестве меры предосторожности, так как я не уверен, насколько хорошо R на Windows обрабатывает коды кода Unicode U+10000 и больше (пять или шесть цифр). Очевидно, что он не может правильно напечатать такие кодовые точки (как показано в примере U+1F60E), а ввод с помощью метода \U + 8 цифр - not possible.

Пример в вопросе показывает, что R (в Windows) может печатать символы Unicode с нотной записью <U+E238>, а не как \ue238. Причина, по-видимому, format(), также используется в print.data.frame(). Например (R для Windows, работает на Wine):

> format("\ue238") 
[1] "<U+E238>" 

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

+0

Это решает проблему. Я понял, что некоторые из смайликов были закодированы как их кодировка софтбанка («»), а остальные - как серия байтов, соответствующих нормальным кодировкам UTF-8 («\ xf0 \ u009f \ u0098»). Почему это должно быть? –

+0

Еще одна проблема: у меня есть карта всех кодировок softbank. («e00e», «e051»), но чтобы сделать этот поиск доступным, мне нужно использовать 'grepl (" \ ue00e ", ...)'. Итак, как добавить «\» в строку? Я попробовал 'paste' и' gsub' с 'fixed = T', но без эффекта. –

+0

Если у вас есть буквальная строка 'abc <-" что-то с "(буквы верхнего регистра) и" карта "со строкой' foo <- "e00e" (строчные буквы), тогда вы будете искать символ, соответствующий 'foo', выполнив что-то вроде' grepl (paste0 (""), abc, fixed = TRUE) '. Но трудно догадаться, какая именно проблема у вас есть. Возможно, вы хотели бы расширить свой вопрос более подробным примером. – mvkorpel