【问题标题】:How to parse key value pair of url string in R with multiple conditions如何在具有多个条件的R中解析url字符串的键值对
【发布时间】:2015-08-19 09:24:59
【问题描述】:

我有一个格式如下的字符串:

a <- c("first_name=James(Mr), cust_id=98503(ZZW_LG,WGE,zonaire),
       StartDate=2015-05-20, EndDate=2015-05-20, performance=best")

我的目标是在如下数据框中获得最终结果:

first_name   cust_id   start_date    end_date    performance           cust_notes
 James(Mr)     98503   2015-05-20  2015-05-20           best   ZZW_LG,WGE,zonaire

我运行了以下代码:

a <- c("first_name=James(Mr), cust_id=98503(ZZW_LG,WGE,zonaire),
       StartDate=2015-05-20, EndDate=2015-05-20, performance=best")

split_by_comma <- strsplit(a,",")

split_by_equal <- lapply(split_by_comma,strsplit,"=")

由于 custid 有额外的逗号和括号,我没有得到想要的结果。

请注意,名字中的括号是真实的,需要原样。

【问题讨论】:

  • 根据您的示例,使用 split_by_comma &lt;- strsplit(a,", ") (逗号后有一个空格)应该可以解决问题。编辑:在尝试您的代码时,我被回车击中,不得不使用两个拆分选项切换到split_by_comma &lt;- strsplit(a,c(", ","\n"),逗号和空格或换行符。仅当您的数据中没有逗号后跟空格时,这才有效。 (不是真正的答案,所以作为评论发布)

标签: regex r strsplit


【解决方案1】:

你需要以此分割。

,(?![^()]*\\))

您需要lookahead。这不会在() 中被, 拆分。参见演示。

https://regex101.com/r/uF4oY4/82

要获得想要的结果,请使用

split_by_comma <- strsplit(a,",(?![^()]*\\))",perl=TRUE)

split_by_equal <- lapply(split_by_comma,strsplit,"=")

【讨论】:

  • 当我在 strsplit(d, ",(?![^()]*\))") 中执行该错误时出现以下错误:无效的正则表达式 ',(?![^( )]*))',原因'无效的正则表达式'
  • 因为perl=T 是 R 正则表达式环视所必需的。
  • @maddykemen 你可以试试perl=T 选项
  • 这里的 custid 一路分裂,我们也有文本部分。这就是我最初遇到问题的地方
  • @maddykemen 您可以稍后使用gsub 删除(?&lt;=\\d)\\(.*?\\) 并替换为space,然后再拆分为=
【解决方案2】:

如果您的字符串格式成立,这可能是一个快速的解决方案:

library(httr)

a <- c("first_name=James(Mr), cust_id=98503(ZZW_LG,WGE,zonaire), StartDate=2015-05-20, 
        EndDate=2015-05-20, performance=best")

dat <- data.frame(parse_url(sprintf("?%s", gsub(",[[:space:]]+", "&", a)))$query, 
           stringsAsFactors=FALSE)

library(tidyr)
library(dplyr)

mutate(separate(dat, cust_id, into=c("cust_id", "cust_notes"), sep="\\("), 
       cust_notes=gsub("\\)", "", cust_notes))

##   first_name cust_id         cust_notes  StartDate    EndDate performance
## 1  James(Mr)   98503 ZZW_LG,WGE,zonaire 2015-05-20 2015-05-20        best

外推:

  • gsub(",[[:space:]]+", "&amp;", a) 使参数看起来像 URL 查询字符串的组成部分。
  • sprintf(…) 让它看起来像一个实际的查询字符串
  • parse_url(来自httr)会将键/值对分离出来,并将它们粘贴到返回列表中的列表(名为query)中
  • data.frame 会,嗯……
  • separate 将为您将( 处的cust_id 列拆分为两列
  • mutate 将删除新 cust_notes 列中的 )

这是一个“管道”的全部内容:

library(httr)
library(tidyr)
library(dplyr)
library(magrittr)

a <- c("first_name=James(Mr), cust_id=98503(ZZW_LG,WGE,zonaire), StartDate=2015-05-20, 
        EndDate=2015-05-20, performance=best")

a %>% 
  gsub(",[[:space:]]+", "&", .) %>% 
  sprintf("?%s", .) %>% 
  parse_url() %>% 
  extract2("query") %>% 
  data.frame(stringsAsFactors=FALSE) %>% 
  separate(cust_id, into=c("cust_id", "cust_notes"), sep="\\(") %>% 
  mutate(cust_notes=gsub("\\)", "", cust_notes))

与推断相匹配并且 (IMO) 更易于遵循。

【讨论】:

  • @hrbmstr 我只能在 cust_id 下获得 98503,而将所有可以放在单独列中的文本部分作为 cust_notes (ZZW_LG,WGE,zonaire)
  • 尝试使用这个 as.numeric(gsub("\\D", "", df$cust_id))
【解决方案3】:

回复较晚,但由于它非常易于理解和实现而无需使用任何其他软件包,因此发布了它

rawdf = read.csv("<your file path>", header = F, sep = ",", stringsAsFactors = F)
# Get the first row of the dataframe and transpose it into a column of a df
colnames = data.frame(t(rawdf[1,]))

# Split the values of the single column df created above into its key value
# pairs which are separated by '=' and save in a vector
colnames = unlist(strsplit(as.character(colnames$X1), "="))

# Pick up all the odd indexed values from the above vector (all odd places
# are colnames and even places the values associated with them)
colnames = colnames[seq(1,length(colnames),2)]

# Assign the extracted column names from the vector above to your original data frame
colnames(rawdf) = colnames

# Use the regex to extract the value in each field of the original df by
# replacing the 'Key=' pattern present in each field with an empty string 
for(i in 1:dim(rawdf)[2]) rawdf[,i] = gsub(paste(colnames[i],"=",sep=""), "", rawdf[,i])

【讨论】:

  • 欢迎来到 StackOverflow。请多解释一下您的解决方案。
猜你喜欢
  • 2011-12-22
  • 2013-10-09
  • 1970-01-01
  • 1970-01-01
  • 2021-01-24
  • 2016-05-04
  • 2020-01-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多