如果它是 "quoted",如何拆分字符串并忽略分隔符
How can I split a string and ignore the delimiter if it's "quoted"
假设我有以下字符串:
params <- "var1 /* first, variable */, var2, var3 /* third, variable */"
我想使用 ,
作为分隔符拆分它,然后提取 "quoted substrings",所以我得到 2 个向量如下:
params_clean <- c("var1","var2","var3")
params_def <- c("first, variable","","third, variable") # note the empty string as a second element.
我在广义上使用术语"quoted",使用任意字符串,这里是/*
和*/
,它们保护子字符串不被拆分。
我找到了一个基于 read.table
的解决方法,事实上它允许引用元素:
library(magrittr)
params %>%
gsub("/\*","_temp_sep_ '",.) %>%
gsub("\*/","'",.) %>%
read.table(text=.,strin=F,sep=",") %>%
unlist %>%
unname %>%
strsplit("_temp_sep_") %>%
lapply(trimws) %>%
lapply(`length<-`,2) %>%
do.call(rbind,.) %>%
inset(is.na(.),value="")
但它非常丑陋和骇人听闻,有什么更简单的方法吗?对于这种情况,我认为必须有一个 regex
可以提供给 strsplit
。
与相关
给你
library(stringr)
params <- "var1 /* first, variable */, var2, var3 /* third, variable */"
# Split by , which are not enclosed in your /*...*/
params_split <- str_split(params, ",(?=[^(/[*])]*(/[*]))")[[1]]
# Extract matches of /*...*/, only taking the contents
params_def <- str_match(params_split, "/[*] *(.*?) *[*]/")[,2]
params_def[is.na(params_def)] <- ""
# Remove traces of /*...*/
params_clean <- trimws(gsub("/[*] *(.*?) *[*]/", "", params_split))
您可以将它包装在一个函数中并使用(没有很好记录的)(*SKIP)(*FAIL)
机制以简单的方式 R
:
getparams <- function(params) {
tmp <- unlist(strsplit(params, "/\*.*?\*/(*SKIP)(*FAIL)|,", perl = TRUE))
params_clean <- vector(length = length(tmp))
params_def <- vector(length = length(tmp))
for (i in seq_along(tmp)) {
# get params_def if available
match <- regmatches(tmp[i], regexec("/\*(.*?)\*/", tmp[i]))
params_def[i] <- ifelse(identical(match[[1]], character(0)), "", trimws(match[[1]][2]))
# params_clean
params_clean[i] <- trimws(gsub("/(.*)\*.*?\*/", "\1", tmp[i]))
}
return(list(params_clean = params_clean, params_def = params_def))
}
params <- "var1 /* first, variable */, var2, var3 /* third, variable */"
getparams(params)
这将使用 (*SKIP)(*FAIL)
(请参阅 a demo on regex101.com)拆分初始字符串,然后分析各个部分。
这会产生一个列表:
$params_clean
[1] "var1" "var2" "var3"
$params_def
[1] "first, variable" "" "third, variable"
或者,更短 sapply
:
getparams <- function(params) {
tmp <- unlist(strsplit(params, "/\*.*?\*/(*SKIP)(*FAIL)|,", perl = TRUE))
(p <- sapply(tmp, function(x) {
match <- regmatches(x, regexec("/\*(.*?)\*/", x))
def <- ifelse(identical(match[[1]], character(0)), "", trimws(match[[1]][2]))
clean <- trimws(gsub("/(.*)\*.*?\*/", "\1", x))
c(clean, def)
}, USE.NAMES = F))
}
这将产生一个矩阵:
[,1] [,2] [,3]
[1,] "var1" "var2" "var3"
[2,] "first, variable" "" "third, variable"
对于后者,您可以获得变量名称,例如result[1,]
.
您可以使用
library(stringr)
cmnt_rx <- "(\w+)\s*(/\*[^*]*\*+(?:[^/*][^*]*\*+)*/)?"
res <- str_match_all(params, cmnt_rx)
params_clean <- res[[1]][,2]
params_clean
## => [1] "var1" "var2" "var3"
params_def <- gsub("^/[*]\s*|\s*[*]/$", "", res[[1]][,3])
params_def[is.na(params_def)] <- ""
params_def
## => [1] "first, variable" "" "third, variable"
正则表达式的主要细节(实际上是(\w+)\s*)(COMMENTS_REGEX)?
):
(\w+)
- 捕获第 1 组:一个或多个单词字符
\s*
- 0+ 个空白字符
(
- 捕获组 2 开始
/\*
- 匹配注释开始/*
[^*]*\*+
- 匹配 *
以外的 0+ 个字符,后跟 1+ 个文字 *
(?:[^/*][^*]*\*+)*
- 0+ 个序列:
[^/*][^*]*\*+
- 不是 /
或 *
(与 [^/*]
匹配)后跟 0+ non-asterisk 个字符 ([^*]*
)后跟 1+ 个星号 (\*+
)
/
- 收盘 /
)?
- 捕获第2组结束,重复1次或0次(表示可选)。
参见regex demo。
gsub
中的 "^/[*]\s*|\s*[*]/$"
模式删除了带有相邻空格的 /*
和 */
。
params_def[is.na(params_def)] <- ""
部分将 NA
替换为空字符串。
假设我有以下字符串:
params <- "var1 /* first, variable */, var2, var3 /* third, variable */"
我想使用 ,
作为分隔符拆分它,然后提取 "quoted substrings",所以我得到 2 个向量如下:
params_clean <- c("var1","var2","var3")
params_def <- c("first, variable","","third, variable") # note the empty string as a second element.
我在广义上使用术语"quoted",使用任意字符串,这里是/*
和*/
,它们保护子字符串不被拆分。
我找到了一个基于 read.table
的解决方法,事实上它允许引用元素:
library(magrittr)
params %>%
gsub("/\*","_temp_sep_ '",.) %>%
gsub("\*/","'",.) %>%
read.table(text=.,strin=F,sep=",") %>%
unlist %>%
unname %>%
strsplit("_temp_sep_") %>%
lapply(trimws) %>%
lapply(`length<-`,2) %>%
do.call(rbind,.) %>%
inset(is.na(.),value="")
但它非常丑陋和骇人听闻,有什么更简单的方法吗?对于这种情况,我认为必须有一个 regex
可以提供给 strsplit
。
与
给你
library(stringr)
params <- "var1 /* first, variable */, var2, var3 /* third, variable */"
# Split by , which are not enclosed in your /*...*/
params_split <- str_split(params, ",(?=[^(/[*])]*(/[*]))")[[1]]
# Extract matches of /*...*/, only taking the contents
params_def <- str_match(params_split, "/[*] *(.*?) *[*]/")[,2]
params_def[is.na(params_def)] <- ""
# Remove traces of /*...*/
params_clean <- trimws(gsub("/[*] *(.*?) *[*]/", "", params_split))
您可以将它包装在一个函数中并使用(没有很好记录的)(*SKIP)(*FAIL)
机制以简单的方式 R
:
getparams <- function(params) {
tmp <- unlist(strsplit(params, "/\*.*?\*/(*SKIP)(*FAIL)|,", perl = TRUE))
params_clean <- vector(length = length(tmp))
params_def <- vector(length = length(tmp))
for (i in seq_along(tmp)) {
# get params_def if available
match <- regmatches(tmp[i], regexec("/\*(.*?)\*/", tmp[i]))
params_def[i] <- ifelse(identical(match[[1]], character(0)), "", trimws(match[[1]][2]))
# params_clean
params_clean[i] <- trimws(gsub("/(.*)\*.*?\*/", "\1", tmp[i]))
}
return(list(params_clean = params_clean, params_def = params_def))
}
params <- "var1 /* first, variable */, var2, var3 /* third, variable */"
getparams(params)
这将使用 (*SKIP)(*FAIL)
(请参阅 a demo on regex101.com)拆分初始字符串,然后分析各个部分。
这会产生一个列表:
$params_clean
[1] "var1" "var2" "var3"
$params_def
[1] "first, variable" "" "third, variable"
或者,更短
sapply
:
getparams <- function(params) {
tmp <- unlist(strsplit(params, "/\*.*?\*/(*SKIP)(*FAIL)|,", perl = TRUE))
(p <- sapply(tmp, function(x) {
match <- regmatches(x, regexec("/\*(.*?)\*/", x))
def <- ifelse(identical(match[[1]], character(0)), "", trimws(match[[1]][2]))
clean <- trimws(gsub("/(.*)\*.*?\*/", "\1", x))
c(clean, def)
}, USE.NAMES = F))
}
这将产生一个矩阵:
[,1] [,2] [,3]
[1,] "var1" "var2" "var3"
[2,] "first, variable" "" "third, variable"
对于后者,您可以获得变量名称,例如result[1,]
.
您可以使用
library(stringr)
cmnt_rx <- "(\w+)\s*(/\*[^*]*\*+(?:[^/*][^*]*\*+)*/)?"
res <- str_match_all(params, cmnt_rx)
params_clean <- res[[1]][,2]
params_clean
## => [1] "var1" "var2" "var3"
params_def <- gsub("^/[*]\s*|\s*[*]/$", "", res[[1]][,3])
params_def[is.na(params_def)] <- ""
params_def
## => [1] "first, variable" "" "third, variable"
正则表达式的主要细节(实际上是(\w+)\s*)(COMMENTS_REGEX)?
):
(\w+)
- 捕获第 1 组:一个或多个单词字符\s*
- 0+ 个空白字符(
- 捕获组 2 开始/\*
- 匹配注释开始/*
[^*]*\*+
- 匹配*
以外的 0+ 个字符,后跟 1+ 个文字*
(?:[^/*][^*]*\*+)*
- 0+ 个序列:[^/*][^*]*\*+
- 不是/
或*
(与[^/*]
匹配)后跟 0+ non-asterisk 个字符 ([^*]*
)后跟 1+ 个星号 (\*+
)
/
- 收盘/
)?
- 捕获第2组结束,重复1次或0次(表示可选)。
参见regex demo。
gsub
中的 "^/[*]\s*|\s*[*]/$"
模式删除了带有相邻空格的 /*
和 */
。
params_def[is.na(params_def)] <- ""
部分将 NA
替换为空字符串。