R:trim 字符串集中的连续尾随和前导特殊字符
R: trim consecutive trailing and leading special characters from set of strings
我有一个字符向量列表,所有字符向量的长度都相等。示例数据:
> a = list('**aaa', 'bb*bb', 'cccc*')
> a = sapply(a, strsplit, '')
> a
[[1]]
[1] "*" "*" "a" "a" "a"
[[2]]
[1] "b" "b" "*" "b" "b"
[[3]]
[1] "c" "c" "c" "c" "*"
我想识别字符 *
的所有前导和尾随 连续 次出现的索引。然后我想从列表中的 所有三个向量 中删除这些索引。通过尾随和前导连续字符我的意思是例如要么像第三个 (cccc*
) 那样只出现一次,要么像第一个 (**aaa
) 那样连续出现多次。
删除后,所有三个字符向量的长度应该仍然相同。
所以前两个和最后一个字符应该从所有三个向量中删除。
[[1]]
[1] "a" "a"
[[2]]
[1] "*" "b"
[[3]]
[1] "c" "c"
请注意,所需结果的第二个向量仍将有一个前导 *
,但它在操作后成为第一个字符,因此它应该在。
我尝试使用 which
来识别索引 (sapply(a, function(x)which(x=='*'))
),但这仍然需要一些代码来检测尾随的索引。
有什么简单的解决方案吗?
首先,就像 Richard Scriven 在他对你的问题的评论中所问的那样,你的输出与你要求的不一样。您要求删除前导字符和尾随字符,但给定的理想输出只是字符列表的第 3 个和第 4 个元素。
这很容易通过
之类的东西实现
a <- list('**aaa', 'bb*bb', 'cccc*')
alist = sapply(a, strsplit, '')
lapply(alist, function(x) x[3:4])
现在回答你的问题:
恕我直言,此处不需要 sapply()
。
您需要 grep 家族的一个函数来直接对您的角色进行操作,这些角色都共享一个由 ?grep 打开的 R 中的帮助页面。
我建议 gsub()
和一些正则表达式来解决你的问题:
a <- list('**aaa', 'bb*bb', 'cccc*')
b <- gsub(pattern = "^(\*)*", x = a, replacement = "")
c <- gsub(pattern = "(\*)*$", x = b, replacement = "")
> c
[1] "aaa" "bb*bb" "cccc"
这在一个正则表达式中是可行的,但是我认为你需要对两者之间的内容进行反向引用,而我没有让它起作用。
如果您熟悉 magrittr 包及其出色的管道运算符,则可以更优雅地执行此操作:
library(magrittr)
gsub(pattern = "^(\*)*", x = a, replacement = "") %>%
gsub(pattern = "(\*)*$", x = ., replacement = "")
我会用 NA
:
替换前导星和滞后星
aa <- lapply(setNames(a,seq_along(a)), function(x) {
star = x=="*"
toNA = cumsum(!star) == 0 | rev(cumsum(rev(!star))) == 0
replace(x, toNA, NA)
})
存储在 data.frame:
DF <- do.call(data.frame, c(aa, list(stringsAsFactors=FALSE)) )
省略所有包含 NA
的行:
res <- na.omit(DF)
# X1 X2 X3
# 3 a * c
# 4 a b c
如果您讨厌 data.frame 并希望返回您的列表:lapply(res,I)
或 c(unclass(res))
,这会给出
$X1
[1] "a" "a"
$X2
[1] "*" "b"
$X3
[1] "c" "c"
我有一个字符向量列表,所有字符向量的长度都相等。示例数据:
> a = list('**aaa', 'bb*bb', 'cccc*')
> a = sapply(a, strsplit, '')
> a
[[1]]
[1] "*" "*" "a" "a" "a"
[[2]]
[1] "b" "b" "*" "b" "b"
[[3]]
[1] "c" "c" "c" "c" "*"
我想识别字符 *
的所有前导和尾随 连续 次出现的索引。然后我想从列表中的 所有三个向量 中删除这些索引。通过尾随和前导连续字符我的意思是例如要么像第三个 (cccc*
) 那样只出现一次,要么像第一个 (**aaa
) 那样连续出现多次。
删除后,所有三个字符向量的长度应该仍然相同。
所以前两个和最后一个字符应该从所有三个向量中删除。
[[1]]
[1] "a" "a"
[[2]]
[1] "*" "b"
[[3]]
[1] "c" "c"
请注意,所需结果的第二个向量仍将有一个前导 *
,但它在操作后成为第一个字符,因此它应该在。
我尝试使用 which
来识别索引 (sapply(a, function(x)which(x=='*'))
),但这仍然需要一些代码来检测尾随的索引。
有什么简单的解决方案吗?
首先,就像 Richard Scriven 在他对你的问题的评论中所问的那样,你的输出与你要求的不一样。您要求删除前导字符和尾随字符,但给定的理想输出只是字符列表的第 3 个和第 4 个元素。 这很容易通过
之类的东西实现a <- list('**aaa', 'bb*bb', 'cccc*')
alist = sapply(a, strsplit, '')
lapply(alist, function(x) x[3:4])
现在回答你的问题:
恕我直言,此处不需要 sapply()
。
您需要 grep 家族的一个函数来直接对您的角色进行操作,这些角色都共享一个由 ?grep 打开的 R 中的帮助页面。
我建议 gsub()
和一些正则表达式来解决你的问题:
a <- list('**aaa', 'bb*bb', 'cccc*')
b <- gsub(pattern = "^(\*)*", x = a, replacement = "")
c <- gsub(pattern = "(\*)*$", x = b, replacement = "")
> c
[1] "aaa" "bb*bb" "cccc"
这在一个正则表达式中是可行的,但是我认为你需要对两者之间的内容进行反向引用,而我没有让它起作用。
如果您熟悉 magrittr 包及其出色的管道运算符,则可以更优雅地执行此操作:
library(magrittr)
gsub(pattern = "^(\*)*", x = a, replacement = "") %>%
gsub(pattern = "(\*)*$", x = ., replacement = "")
我会用 NA
:
aa <- lapply(setNames(a,seq_along(a)), function(x) {
star = x=="*"
toNA = cumsum(!star) == 0 | rev(cumsum(rev(!star))) == 0
replace(x, toNA, NA)
})
存储在 data.frame:
DF <- do.call(data.frame, c(aa, list(stringsAsFactors=FALSE)) )
省略所有包含 NA
的行:
res <- na.omit(DF)
# X1 X2 X3
# 3 a * c
# 4 a b c
如果您讨厌 data.frame 并希望返回您的列表:lapply(res,I)
或 c(unclass(res))
,这会给出
$X1
[1] "a" "a"
$X2
[1] "*" "b"
$X3
[1] "c" "c"