4

假设一个向量:

xx.1 <- c("zz_ZZ_uu_d", "II_OO_d")

我想得到一个从最右边分裂的新向量,并且只分裂一次。预期结果将是:

c("zz_ZZ_uu", "d", "II_OO", "d").

这就像python的rsplit()函数。我目前的想法是反转字符串,并用str_split()in分割stringr

有更好的解决方案吗?

更新
这是我返回 n 个拆分的解决方案,具体取决于 stringr 和 stringi。有人提供具有基本功能的版本会很好。

rsplit <- function (x, s, n) {
  cc1 <- unlist(stringr::str_split(stringi::stri_reverse(x), s, n))
  cc2 <- rev(purrr::map_chr(cc1, stringi::stri_reverse))
  return(cc2)
}
4

5 回答 5

6

负前瞻:

unlist(strsplit(xx.1, "_(?!.*_)", perl = TRUE))
# [1] "zz_ZZ_uu" "d"        "II_OO"    "d"     

Wherea(?!b)说要找到这样的 a awhich 后面没有 a b。在这种情况下.*_,意味着无论多远 ( .*) 都不应该再有_'s。

但是,要概括这个想法似乎并不容易。首先,请注意它可以被重写为正向前瞻_(?=[^_]*$)(find_后跟除 之外的任何内容_,这里$表示字符串的结尾)。那么一个不太优雅的概括将是

rsplit <- function(x, s, n) {
  p <- paste0("[^", s, "]*")
  rx <- paste0(s, "(?=", paste(rep(paste0(p, s), n - 1), collapse = ""), p, "$)")
  unlist(strsplit(x, rx, perl = TRUE))
}

rsplit(vec, "_", 1)
# [1] "a_b_c_d_e_f" "g"           "a"           "b"          
rsplit(vec, "_", 3)
# [1] "a_b_c_d" "e_f_g"   "a_b"    

例如,如果n=3这个函数使用_(?=[^_]*_[^_]*_[^_]*$).

于 2013-12-08T15:23:38.143 回答
2

还有两个。在两者中,我都使用"(.*)_(.*)"作为模式来捕获字符串的两个部分。请记住,这*是贪婪的,因此第一个(.*)将匹配尽可能多的字符。

在这里,我regexec用来捕获您的子字符串的开始和结束位置,并regmatches重建它们:

unlist(lapply(regmatches(xx.1, regexec("(.*)_(.*)", xx.1)),
              tail, -1))

而这个学术性稍差,但易于理解:

unlist(strsplit(sub("(.*)_(.*)", "\\1@@@\\2", xx.1), "@@@"))
于 2013-12-08T17:49:50.070 回答
1

拆开后再贴回去怎么样?

rsplit <- function( x, s ) {
  spl <- strsplit( "zz_ZZ_uu_d", s, fixed=TRUE )[[1]]
  res <- paste( spl[-length(spl)], collapse=s, sep="" )
  c( res, spl[length(spl)]  )
}
> rsplit("zz_ZZ_uu_d", "_")
[1] "zz_ZZ_uu" "d"  
于 2013-12-08T15:14:54.037 回答
1

我也想过一种与阿里非常相似的方法

> res <- lapply(strsplit(xx.1, "_"), function(x){
    c(paste0(x[-length(x)], collapse="_" ), x[length(x)])
  }) 

> unlist(res)
[1] "zz_ZZ_uu" "d"        "II_OO"    "d"  
于 2013-12-08T15:20:18.220 回答
0

这正是您想要的,并且是最简单的方法:

require(stringr)
as.vector(t(str_match(xx.1, '(.*)_(.*)') [,-1]))
[1] "zz_ZZ_uu" "d"        "II_OO"    "d"

解释:

  • str_split()不是您要查找的机器人,因为它只进行从左到右的拆分,然后拆分然后重新粘贴所有 (n-1) 个最左侧的匹配完全是浪费时间。所以使用str_split()带有两个捕获组的正则表达式。请注意,第一个(.*)_将贪婪匹配直到最后一次出现的所有内容_,这就是您想要的。(如果没有至少一个_,这将失败,并返回 NAs)
  • str_match()返回一个矩阵,其中第一列是整个字符串,后续列是单独的捕获组。我们不想要第一列,所以将其删除[,-1]
  • as.vector()将按列展开该矩阵,这不是您想要的,因此我们使用t()转置它以按行展开
  • str_match(string, pattern)在字符串和模式上进行矢量化,这很整洁
于 2016-09-21T06:19:36.573 回答