【问题标题】:r How to parse pretty-printed JSON with newlines within character stringsr 如何用字符串中的换行符解析漂亮打印的 JSON
【发布时间】:2019-07-10 17:10:23
【问题描述】:

我正在努力解析 R 中的 JSON,它在字符串中和键/值对(和整个对象)之间都包含换行符。

我的意思是这种格式:

{
    "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 格式,但没有一个专门的软件包可以处理它。有人建议streaming in the data with either jsonlite or ndjsonor this onethis one)。其他人建议mapping the function across lines (or similarly in base R)。

一切都会引发以下错误之一: Error: parse error: trailing garbageError: parse error: premature EOF 或打开文本连接时出现问题。

有人有解决办法吗?

【问题讨论】:

  • 那个块(作为一个整体)是不合法的json,这两个字典通常是(a)在一个列表中,还是(b)逐行存储行,ndjson 风格?
  • jsonlite::prettify( ) 是否适合您?
  • 嗨@r2evans,不,这是我必须使用的 - 我看不出有什么方法可以将它强制转换回这两种格式中的任何一种......
  • 谢谢@Dave2e - 我刚刚尝试minify 作为第一步,但它以与我其他尝试阅读它的方式类似的方式失败......

标签: r json parsing newline ndjson


【解决方案1】:

编辑

知道 json 格式错误,我们会损失一些 ndjson 效率,但我认为我们可以实时修复它,假设我们显然有一个右括号(}) 后跟空白或一些空格(包括换行符)后跟左大括号 ({)

fn <- "~/StackOverflow/TomWagstaff.json"
wrongjson <- paste(readLines(fn), collapse = "")
if (grepl("\\}\\s*\\{", wrongjson))
  wrongjson <- paste0("[", gsub("\\}\\s*\\{", "},{", wrongjson), "]")
json <- jsonlite::fromJSON(wrongjson, simplifyDataFrame = FALSE)
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 或类似名称保存。

【讨论】:

  • 感谢@r2evans,看来我遇到了一个不是合法 JSON 的文件...
猜你喜欢
  • 1970-01-01
  • 2014-11-09
  • 2013-07-07
  • 1970-01-01
  • 2020-11-19
  • 2016-03-23
  • 2015-04-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多