如何在R中正确拆分带部分引号的逗号分隔字符串?
处理PostgreSQL返回的特殊格式字符串拆分问题
问题场景
在R语言中,处理从PostgreSQL查询得到的data.frame列时,会遇到一种特殊格式的字符串:它们是逗号分隔的列表,但仅当值包含空格、双引号或逗号时才用双引号包裹;值中的字面双引号用\"转义。由于无法修改PostgreSQL端的输出格式,直接按逗号拆分这些字符串会因特殊字符干扰导致错误。需要正确拆分如下示例:
- 输入
{'a',b},拆分结果为c("'a'","b") - 输入
{"abc, def","the \\\"big\\\" one",fgh},拆分结果为c("abc, def","the \"big\" one","fgh")
原繁琐实现方案
之前曾实现了一套逻辑复杂的处理代码:
# 从PostgreSQL查询创建data.frame con <- DBI::dbConnect(RPostgres::Postgres()) q = "WITH a(v) AS (VALUES(ARRAY['''a''','b']::varchar[]),(ARRAY['abc, def','the \"big\" one','fgh']::varchar[])) SELECT * FROM a" x <- DBI::dbGetQuery(con,q) # 拆分带引号的字符串,避开值内部的转义引号 xx = gsub("[\\][\"]","%myspecialquote%",x$v) # 保护转义引号 y = stringi::stri_extract_all_regex(xx, '(?<=[{"]).*?(?=["}])') yy = lapply(y,\(.) gsub("%myspecialquote%","\"",.)) # 恢复引号 z = lapply(yy,\(.) .[.!="," & .!=""]) # 移除空字符串和单独的逗号 # 拆分未被正确拆分的部分 w = lapply(1:length(z),\(.) { t = ifelse(grepl("\"",x$v[.]),z[.],strsplit(z[[.]],","))[[1]] t = lapply(t,\(.) ifelse(grepl("^,",.) | grepl(",$",.),(gsub("^[,]|[,]$","",.) |> strsplit(","))[[1]],.)) return(t) }) # 合并结果 v=sapply(w,\(.) { if(is.list(.)) . = do.call(c,.) return(.) })
优化后的简洁方案
基于整理的优化建议,这里提供一套更简洁的实现方式(注意需要确保原始值中不包含%myspecialquote%这个自定义标记):
x <- data.frame(v = c("{'a',b}", '{"abc, def","the \\\"big\\\" one",fgh}')) out <- transform(x, v = lapply(v, function(x) x |> gsub("^[{]|[}]$", "", x = _) |> # 移除首尾的大括号 gsub("[\\][\"]","%myspecialquote%",x = _) |> # 替换转义引号为临时标记 scan(text = _, quote = '"', what = "", sep = ",", quiet = TRUE) |> # 用scan处理带引号的拆分 gsub("%myspecialquote%","\"",x = _) # 恢复转义引号 ))
如果使用tidyverse生态,可以将代码中的transform替换为mutate。
内容的提问来源于stack exchange,提问作者David M. Kaplan
相关产品推荐
相关产品推荐

