解析R中的嵌套结构

时间:2017-12-21 13:01:14

标签: json r parsing nested string-parsing

我有一个类似json的字符串,表示嵌套结构。它不是一个真正的json,因为名称和值没有被引用。我想将其解析为嵌套结构,例如列表清单。

#example:
x_string = "{a=1, b=2, c=[1,2,3], d={e=something}}"

,结果应该是这样的:

x_list = list(a=1,b=2,c=c(1,2,3),d=list(e="something"))

是否有任何方便的功能,我不知道这种解析?

感谢。

2 个答案:

答案 0 :(得分:1)

如果您的所有数据都是一致的,那么有一个简单的解决方案,涉及regex和jsonlite包。代码是:

if(!require(jsonlite, quiet=TRUE)){ 
    #if library is not installed: installs it and loads it into the R session for use.

    install.packages("jsonlite",repos="https://ftp.heanet.ie/mirrors/cran.r-project.org")
    library(jsonlite)
}

x_string = "{a=1, b=2, c=[1,2,3], d={e=something}}"

json_x_string = "{\"a\":1, \"b\":2, \"c\":[1,2,3], \"d\":{\"e\":\"something\"}}"
fromJSON(json_x_string)

s <- gsub( "([A-Za-z]+)", "\"\\1\"",  gsub( "([A-Za-z]*)=", "\\1:", x_string ) )

fromJSON( s )

第一部分检查是否已安装软件包。如果它是加载它,否则它安装它然后加载它。我通常将其包含在我正在编写的任何R代码中,以便在pcs / people之间进行转换更简单。

你的字符串是x_string,我们希望它看起来像json_x_string,它在我们调用fromJSON()时给出了所需的输出。

正则表达式分为两部分,因为它已经有一段时间了 - 我很确定这可以变得更优雅。然后,这取决于你的数据是否一致,所以我现在就这样离开。首先,它将“=”更改为“:”,然后在所有字母组周围添加引号。调用fromJSON(s)给出输出:

  

fromJSON(s)

     

$ a

     

[1] 1

     

$ b

     

[1] 2

     

$ c

     

[1] 1 2 3

     

$ d

     

$ d $ e

     

[1]“某事”

答案 1 :(得分:0)

我宁愿避免使用JSON的解析,因为缺乏可扩展性和灵活性,并坚持使用正则表达式+递归的解决方案。

这是一个可扩展基本代码,可根据需要解析您的输入字符串

主递归函数:

# Parse string
parse.string = function(.string){
  regex = "^((.*)=)??\\{(.*)\\}"

  # Recursion termination: element parsing
  if(iselement(.string)){
    return(parse.element(.string))
  }

  # Extract components 
  elements.str = gsub(regex, "\\3", .string)
  elements.vector = get.subelements(elements.str)

  # Recursively parse each element
  parsed.elements = list(sapply(elements.vector, parse.string, USE.NAMES = F))

  # Extract list's name and return 
  name = gsub(regex, "\\2", .string)
  names(parsed.elements) = name
  return(parsed.elements)
}

帮助功能:

library(stringr)

# Test if the string is a base element
iselement = function(.string){
  grepl("^[^[:punct:]]+=[^\\{\\}]+$", .string)
}

# Parse element
parse.element = function(element.string){
  splits = strsplit(element.string, "=")[[1]]
  element = splits[2]

  # Parse numeric elements
  if(!is.na(as.numeric(element))){
    element = as.numeric(element)
  }

  # TODO: Extend here to include vectors

  # Reformat and return 
  element = list(element)
  names(element) = splits[1]
  return(element)
}

# Get subelements from a string
get.subelements = function(.string){
  # Regex of allowed elements - Extend here to include more types 
  elements.regex = c("[^, ]+?=\\{.+?\\}", #Sublist
                     "[^, ]+?=\\[.+?\\]", #Vector
                     "[^, ]+?=[^=,]+")    #Base element
  str_extract_all(.string, pattern = paste(elements.regex, collapse = "|"))[[1]]
}

解析结果:

string = "{a=1, b=2, c=[1,2,3], d={e=something}}"
string_2 = "{a=1, b=2, c=[1,2,3], d=somthing}"
named_string = "xyz={a=1, b=2, c=[1,2,3], d={e=something, f=22}}"
named_string_2 = "xyz={d={e=something, f=22}}"

parse.string(string)
# [[1]]
# [[1]]$a
# [1] 1
# 
# [[1]]$b
# [1] 2
# 
# [[1]]$c
# [1] "[1,2,3]"
# 
# [[1]]$d
# [[1]]$d$e
# [1] "something"