在第一个/第n个分隔符出现时拆分

时间:2014-10-10 14:10:55

标签: regex r

我正在尝试一些我认为很容易的事情。我正在寻找一个单一的正则表达式解决方案(虽然其他人欢迎完整性)。我想拆分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)))

4 个答案:

答案 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)。

Demo on regex101

这就是计划。但是,strsplit似乎有不同的看法。

实际执行

Demo on ideone.com

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下划线出现时进行拆分。

RegEx Demo

更新:似乎R也支持PCRE,在这种情况下,您也可以使用此PCRE正则表达式执行split

^((?:[^_]*_){1}[^_]*)(*SKIP)(*F)|_

1替换为n-1,您尝试在nth下划线出现时进行拆分。

  • (*FAIL)表现得像一个失败的否定断言,是(?!)
  • 的同义词
  • (*SKIP)定义了一个点,当子模式稍后失败时,不允许正则表达式引擎回溯
  • (*SKIP)(*FAIL)一起提供了一个很好的限制替代方案,在上面的正则表达式中你不能有一个可变长度的lookbehind。

RegEx Demo2

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部分。