Разбор строки Unicode с нулями в R
У меня возникли проблемы с анализом строки Unicode и объекта JSON, извлеченного из API. Как строка имеет Encoding()
как "неизвестно", мне нужно разобрать его, чтобы система знала, с чем он имеет дело. Строка представляет декодированный файл.png в UTF-8, который мне нужно затем декодировать обратно в latin1, прежде чем записать его в файл.png (я знаю, что это очень задом наперед, и было бы намного лучше, если бы API выдвинул строку base64-string).
Я получаю строку из API как chr
объект, и попытайтесь позволить fromJSON делать работу, но не игра в кости. Обрезает строку при первом нуле (\u0000
).
> library(httr)
> library(jsonlite)
> library(tidyverse)
> m
Response [https://...]
Date: 2018-04-10 11:47
Status: 200
Content-Type: application/json
Size: 24.3 kB
{"artifact": "\u0089PNG\r\n\u001a\n\u0000\u0000\u0000\rIHDR\u0000\u0000\u0000\u0092\u0000\u0000\u0000\u00e3...
> x <- content(m, encoding = "UTF-8", as = "text")
> ## substing of the complete x:
> x <- "{\"artifact\": \"\\u0089PNG\\r\\n\\u001a\\n\\u0000\\u0000\\u0000\\rIHDR\\u0000\\u0000\\u0000\\u0092\\u0000\\u0000\\u0000\\u00e3\\b\\u0006\\u0000\\u0000\\u0000n\\u0005M\\u00ea\\u0000\\u0000\\u0000\\u0006bKGD\\u0000\\u00ff\\u0000\\u00ff\\u0000\\u00ff\\u00a0\\u00bd\\u00a7\\u0093\\u0000\\u0000\\u0016\\u00e7IDATx\\u009c\\u00ed\"}\n"
>
> ## the problem
> "\u0000"
Error: nul character not allowed (line 1)
> ## this works fine
> "\\u0000"
[1] "\\u0000"
>
> y <- fromJSON(txt = x)
> y # note how the string is cut!
$artifact
[1] "\u0089PNG\r\n\032\n"
Когда я заменяю \\u0000
с char(0)
все работает нормально. Проблема в том, что нулевые значения играют важную роль в двоичном представлении файла, в который я пишу в конце, что приводит к повреждению получающегося изображения в средстве просмотра.
> x <- str_replace_all(string = x, pattern = "\\\\u0000", replacement = chr(0))
> y <- fromJSON(txt = x)
> y
$artifact
[1] "\u0089PNG\r\n\032\n\rIHDR\u0092ã\b\006n\005Mê\006bKGDÿÿÿ ½§\u0093\026çIDATx\u009cí"
> str(y$artifact)
chr "<U+0089>PNG\r\n\032\n\rIHDR<U+0092>ã\b\006n\005Mê\006bKGDÿÿÿ ½§<U+0093>\026çIDATx<U+009C>í"
> Encoding(y$artifact)
[1] "UTF-8"
> z <- iconv(y$artifact, from = "UTF-8", to = "latin1")
> writeBin(object = z, con = "test.png", useBytes = TRUE)
Я пробовал эти команды с оригинальной строкой, но безрезультатно
> library(stringi)
> stri_unescape_unicode(str = x)
Error in stri_unescape_unicode(str = x) :
embedded nul in string: '{"artifact": "<U+0089>PNG\r\n\032\n'
> ## and
> parse(text = x)
Error in parse(text = x) : nul character not allowed (line 1)
R не может обработать этот нулевой символ? Любая идея о том, как я могу получить полную закодированную строку и записать ее в файл?
Та же самая история прекрасно работает в Python, который использует \x
конвенция вместо \u00
response = r.json()
artifact = response['artifact']
artifact
'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR....'
artifact_encoded = artifact.encode('latin-1')
artifact_encoded # note the binary form!
b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR....'
fh = open("abc.png", "wb")
fh.write(artifact_encoded)
fh.close()
К вашему сведению: я вырезал большую часть фактической строки, но достаточно для использования в целях тестирования. Фактическая строка содержала другие символы, и казалось невозможным скопировать и вставить строку в скрипт и присвоить ее новой переменной (например, y <- "{\"artifact\": \"\\u0089PNG\\..."
). Итак, я не знаю, что бы я делал, если бы мне пришлось читать строку, например, из файла.csv..
Любые указатели в любой моей борьбе будут оценены:)