Как проанализировать красиво напечатанный JSON с символами новой строки в символьных строках - PullRequest
0 голосов
/ 10 июля 2019

Я пытаюсь проанализировать JSON в R, который содержит символы новой строки как внутри строк символов, так и между парами ключ / значение (и целыми объектами).

Вот такой формат я имею в виду:

{
    "id": 123456,
    "name": "Try to parse this",
    "description": "Thought reading a JSON was easy? \r\n Try parsing a newline within a string."
}
{
    "id": 987654,
    "name": "Have another go",
    "description": "Another two line description... \r\n With 2 lines."
}

Скажите, что я сохранил этот JSON как example.json. Я пробовал различные методы, чтобы преодолеть проблемы синтаксического анализа, предложенные в другом месте на SO Ни одна из следующих работ:

library(jsonlite)

foo <- readLines("example.json")
foo <- paste(readLines("example.json"), collapse = "")

bar <- fromJSON(foo)
bar <- jsonlite::stream_in(textConnection(foo))
bar <- purrr::map(foo, jsonlite::fromJSON)
bar <- ndjson::stream_in(textConnection(foo))
bar <- read_json(textConnection(foo), format = "jsonl")

Я понимаю, что это действительно формат NDJSON, но ни один из специализированных пакетов не справляется с этим. Некоторые предлагают потоковую передачу данных с помощью jsonlite или ndjson ( или этот и этот ). Другие предлагают отображать функцию на линии ( или аналогично в базе R ).

Все вызывает одну из следующих ошибок: Error: parse error: trailing garbage или Error: parse error: premature EOF или проблемы с открытием текстового соединения.

У кого-нибудь есть решение?

1 Ответ

0 голосов
/ 10 июля 2019

Редактировать

Зная, что json неправильно отформатирован, мы теряем некоторую эффективность ndjson, но я думаю, что мы можем исправить это в реальном времени, при условии что у нас явно есть закрывающая скобка (}), за которой ничего не стоит или пробелы (включая переводы строк), за которыми следует открывающая скобка ({)

fn <- "~/StackOverflow/TomWagstaff.json"
wrongjson <- paste(readLines(fn), collapse = "")
if (grepl("\\}\\s*\\{", wrongjson))
  wrongjson <- paste0("[", gsub("\\}\\s*\\{", "},{", wrongjson), "]")
str(json)
# List of 2
#  $ :List of 3
#   ..$ id         : int 123456
#   ..$ name       : chr "Try to parse this"
#   ..$ description: chr "Thought reading a JSON was easy? \r\n Try parsing a newline within a string."
#  $ :List of 3
#   ..$ id         : int 987654
#   ..$ name       : chr "Have another go"
#   ..$ description: chr "Another two line description... \r\n With 2 lines."

Отсюда выможно продолжить с

txtjson <- paste(sapply(json, jsonlite::toJSON, pretty = TRUE), collapse = "\n")

(Ниже приведен исходный ответ, в котором мы надеемся / предполагаем, что формат был каким-то законным.)


Предположим, что ваши данные на самом деле таковы:

{"id":123456,"name":"Try to parse this","description":"Thought reading a JSON was easy? \r\n Try parsing a newline within a string."}
{"id": 987654,"name":"Have another go","description":"Another two line description... \r\n With 2 lines."}

тогда это как вы подозреваете ndjson.Из этого вы можете сделать это:

fn <- "~/StackOverflow/TomWagstaff.json"
json <- jsonlite::stream_in(file(fn), simplifyDataFrame = FALSE)
# opening file input connection.
#  Imported 2 records. Simplifying...
# closing file input connection.
str(json)
# List of 2
#  $ :List of 3
#   ..$ id         : int 123456
#   ..$ name       : chr "Try to parse this"
#   ..$ description: chr "Thought reading a JSON was easy? \r\n Try parsing a newline within a string."
#  $ :List of 3
#   ..$ id         : int 987654
#   ..$ name       : chr "Have another go"
#   ..$ description: chr "Another two line description... \r\n With 2 lines."

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

cat(sapply(json, jsonlite::toJSON, pretty = TRUE), sep = "\n")
# {
#   "id": [123456],
#   "name": ["Try to parse this"],
#   "description": ["Thought reading a JSON was easy? \r\n Try parsing a newline within a string."]
# }
# {
#   "id": [987654],
#   "name": ["Have another go"],
#   "description": ["Another two line description... \r\n With 2 lines."]
# }

Если вы хотите, чтобы вывести его в файл таким способом (хотя ничто в jsonlite или подобном не сможет прочитать его, так как этобольше не является юридическим ndjson или юридическим json в целом), тогда вы можете

txtjson <- paste(sapply(json, jsonlite::toJSON, pretty = TRUE), collapse = "\n")

и затем сохранить его с помощью writeLines или аналогичного.

...