【问题标题】:R: trim consecutive trailing and leading special characters from set of stringsR:从字符串集中修剪连续的尾随和前导特殊字符
【发布时间】:2015-11-30 19:39:14
【问题描述】:

我有一个字符向量列表,长度都相等。示例数据:

> 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=='*'))),但这仍然需要一些代码来检测尾随的索引。

对于简单的解决方案有什么想法吗?

【问题讨论】:

  • 你为什么要删除一些字母?
  • 试图澄清问题:如果我在其中一个字符串的开头或结尾找到一个或多个*'s,我想从所有字符串中删除这些索引.所以如果其中一个字符串是**a**,我想从这个字符串和所有其他字符串中删除索引1,2,4,5。
  • 试试i1 <- unlist(gregexpr('(?<=\\*)\\*|\\*(?=\\*)|^\\*|\\*$', unlist(a), perl=TRUE));i2 <- setdiff(seq(nchar(a[[1]])), i1[i1>0]); strsplit(substr(unlist(a), i2[1], i2[2]), '')
  • 这给了我十五个character(0)的列​​表
  • @akrun:我明白了,如果我将它应用于字符串列表而不是字符向量列表,它对我有用。谢谢!

标签: r character


【解决方案1】:

我会用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.frames 并希望恢复您的列表:lapply(res,I) 或 c(unclass(res)),这给出了

$X1
[1] "a" "a"

$X2
[1] "*" "b"

$X3
[1] "c" "c"

【讨论】:

    【解决方案2】:

    首先,就像 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 = "")
    

    【讨论】:

    • 我的理解是sapply只是用来构造示例数据,描述为“字符向量列表”。
    • @Frank:没错,这只是一个简单的玩具示例,用于模拟我的真实数据。如果列表或数据框,我没有偏好,字符向量列表正是我使用的包中的内容。
    • @zerwck:这对我不起作用,所有生成的字符串都应该具有相同的长度...
    猜你喜欢
    • 2014-10-30
    • 1970-01-01
    • 1970-01-01
    • 2014-01-03
    • 2017-04-22
    • 1970-01-01
    • 2015-08-01
    • 2011-06-03
    • 2018-07-23
    相关资源
    最近更新 更多