我正在尝试一些我认为很容易的事情。我正在寻找一个单一的正则表达式解决方案(虽然其他人欢迎完整性)。我想拆分n次出现的分隔符。
以下是一些数据:
x <- "I like_to see_how_too"
pat <- "_"
期望的结果
说我想在第一次出现_
时拆分:
[1] "I like" "to see_how_too"
假设我想在第二次出现_
时拆分:
[1] "I like_to see" "how_too"
理想情况下,如果解决方案是正则表达式,则可以推广到第n次;解决方案将strsplit
与单个正则表达式一起使用。
这是一个不适合我使用strsplit
的单一正则表达式参数的解决方案
x <- "I like_to see_how_too"
y <- "_"
n <- 1
loc <- gregexpr("_", x)[[1]][n]
c(substr(x, 1, loc-1), substr(x, loc + 1, nchar(x)))
答案 0 :(得分:6)
这是使用gsubfn
包和一些regex-fu的另一种解决方案。要更改分隔符的nth
次出现,您只需交换放置在量词范围内的数字 - {n}
。
library(gsubfn)
x <- 'I like_to see_how_too'
strapply(x, '((?:[^_]*_){1})(.*)', c, simplify =~ sub('_$', '', x))
# [1] "I like" "to see_how_too"
如果您希望第n次出现用户定义,您可以使用以下内容:
n <- 2
re <- paste0('((?:[^_]*_){',n,'})(.*)')
strapply(x, re, c, simplify =~ sub('_$', '', x))
# [1] "I like_to see" "how_too"
答案 1 :(得分:3)
由于R使用PCRE,您可以使用\K
从主匹配结果中删除与\K
之前的模式匹配的所有内容。
以下是在第3 _
^[^_]*(?:_[^_]*){2}\K_
如果您希望在第{n _
次出现时进行拆分,只需将2
更改为(n - 1)。
这就是计划。但是,strsplit
似乎有不同的看法。
x <- "I like_to see_how_too but_it_seems to_be_impossible"
strsplit(x, "^[^_]*(?:_[^_]*)\\K_", perl=TRUE)
strsplit(x, "^[^_]*(?:_[^_]*){1}\\K_", perl=TRUE)
strsplit(x, "^[^_]*(?:_[^_]*){0}\\K_", perl=TRUE)
# strsplit(x, "^[^_]*(?:_[^_]*)\\K_", perl=TRUE)
# [[1]]
# [1] "I like_to see" "how_too but" "it_seems to" "be_impossible"
# strsplit(x, "^[^_]*(?:_[^_]*){1}\\K_", perl=TRUE)
# [[1]]
# [1] "I like_to see" "how_too but" "it_seems to" "be_impossible"
# strsplit(x, "^[^_]*(?:_[^_]*){0}\\K_", perl=TRUE)
# [[1]]
# [1] "I like" "to see" "how" "too but" "it"
# [6] "seems to" "be" "impossible"
它仍无法使用更强大的断言\A
strsplit(x, "\\A[^_]*(?:_[^_]*){0}\\K_", perl=TRUE)
# [[1]]
# [1] "I like" "to see" "how" "too but" "it"
# [6] "seems to" "be" "impossible"
此行为暗示strsplit
找到第一个匹配,执行子字符串以提取第一个标记和剩余部分,并在剩余部分中找到下一个匹配。
这会删除之前匹配项中的所有状态,而会在尝试匹配其余匹配项时使用干净状态。这使得在第一次匹配时停止strsplit
功能并且同时完成任务的任务变得不可能。 strsplit
中甚至没有参数来限制拆分的数量。
答案 2 :(得分:2)
而不是拆分你匹配得到你的分裂字符串。
试试这个正则表达式:
^((?:[^_]*_){1}[^_]*)_(.*)$
将1
替换为n-1
,您尝试在nth
下划线出现时进行拆分。
更新:似乎R
也支持PCRE,在这种情况下,您也可以使用此PCRE正则表达式执行split
:
^((?:[^_]*_){1}[^_]*)(*SKIP)(*F)|_
将1
替换为n-1
,您尝试在nth
下划线出现时进行拆分。
(*FAIL)
表现得像一个失败的否定断言,是(?!)
(*SKIP)
定义了一个点,当子模式稍后失败时,不允许正则表达式引擎回溯(*SKIP)(*FAIL)
一起提供了一个很好的限制替代方案,在上面的正则表达式中你不能有一个可变长度的lookbehind。x <- "I like_to see_how_too"
strsplit(x, "^((?:[^_]*_){0}[^_]*)(*SKIP)(*F)|_", perl=TRUE)
strsplit(x, "^((?:[^_]*_){1}[^_]*)(*SKIP)(*F)|_", perl=TRUE)
## > strsplit(x, "^((?:[^_]*_){0}[^_]*)(*SKIP)(*F)|_", perl=TRUE)
## [[1]]
## [1] "I like" "to see" "how" "too"
## > strsplit(x, "^((?:[^_]*_){1}[^_]*)(*SKIP)(*F)|_", perl=TRUE)
## [[1]]
## [1] "I like_to see" "how_too"
答案 3 :(得分:2)
这使用gsubfn
来预处理输入字符串,以便strsplit
可以处理它。主要优点是可以指定数字向量k
,指示要分割的下划线。
它将k
定义的下划线的出现替换为双下划线,然后在双下划线上拆分。在这个例子中,我们分为第2和第4下划线:
library(gsubfn)
k <- c(2, 4) # split at 2nd and 4th _
p <- proto(fun = function(., x) if (count %in% k) "__" else "_")
strsplit(gsubfn("_", p, "aa_bb_cc_dd_ee_ff"), "__")
,并提供:
[[1]]
[1] "aa_bb" "cc_dd" "ee_ff"
如果允许空字段,则使用字符串中不包含的任何其他字符序列,例如"\01"
代替双下划线。
有关使用gusbfn
原型对象在匹配项之间保持状态的更多信息,请参阅gusbfn插图的第4部分。