使用R中的正则表达式拆分时忽略字符串的一部分

时间:2017-11-14 13:34:09

标签: r regex

我正在尝试在某些特定点(短划线,strsplit)中拆分R中的字符串(使用-)但是如果短划线位于括号内的字符串内{{1} })。

示例:

[

应该给我一些类似的东西:

xx <- c("Radio Stations-Listened to Past Week-Toronto [FM-CFXJ-93.5 (93.5 The Move)]","Total Internet-Time Spent Online-Past 7 Days")
xx
  [1] "Radio Stations-Listened to Past Week-Toronto [FM-CFXJ-93.5 (93.5 The Move)]"
  [2] "Total Internet-Time Spent Online-Past 7 Days" 

有没有办法用正则表达式来做到这一点?虚线的位置和数量在向量的每个元素内发生变化,并且不总是括号。但是,当有括号时,它们总是在最后。

我尝试了不同的东西,但没有一个在起作用:

list(c("Radio Stations","Listened to Past Week","Toronto [FM-CFXJ-93.5 (93.5 The Move)]"), c("Total Internet","Time Spent Online","Past 7 Days"))
  [[1]]
  [1] "Radio Stations"                         "Listened to Past Week"                 
  [3] "Toronto [FM-CFXJ-93.5 (93.5 The Move)]"

  [[2]]
  [1] "Total Internet"    "Time Spent Online" "Past 7 Days"  

任何帮助都将不胜感激。

3 个答案:

答案 0 :(得分:2)

基于:Regex for matching a character, but not when it's enclosed in square bracket

您可以使用:

importer.ProtocolName = "Soap"; // Woohoo

答案 1 :(得分:2)

要匹配不在-[内的],您必须匹配[]附带的字符串的一部分,省略它,并在所有其他上下文中匹配-。在abc-def]-不在[]之间。不应该对规格进行分割。

完成this regex

\[[^][]*](*SKIP)(*FAIL)|-

下面,

  • \[ - 匹配[
  • [^][]* - 除[]以外的零个或多个字符(如果您使用[^]],它将匹配任何字符,但]
  • ] - 文字]
  • (*SKIP)(*FAIL) - 省略匹配的PCRE动词,并在省略的一个结束后让引擎继续寻找匹配
  • | - 或
  • - - 其他情境中的连字符。

或者,匹配[...[...]类似子串(demo):

\[[^]]*](*SKIP)(*FAIL)|-

或者,考虑嵌套的方括号(demo):

(\[(?:[^][]++|(?1))*])(*SKIP)(*FAIL)|-

在这里,(\[(?:[^][]++|(?1))*])匹配并捕获[,然后是[]以及[^][]++或(|以外的1 +个字符} (?1)递归整个捕获组1模式((...)之间的整个部分)。

请参阅R demo

xx <- c("abc-def]", "Radio Stations-Listened to Past Week-Toronto [FM-CFXJ-93.5 (93.5 The Move)]","Total Internet-Time Spent Online-Past 7 Days")
pattern <- "\\[[^][]*](*SKIP)(*FAIL)|-"
strsplit(xx, pattern, perl=TRUE)
# [[1]]
# [1] "abc"  "def]"
# [[2]]
# [1] "Radio Stations"                        
# [2] "Listened to Past Week"                 
# [3] "Toronto [FM-CFXJ-93.5 (93.5 The Move)]"
# [[3]]
# [1] "Total Internet"    "Time Spent Online" "Past 7 Days"      

pattern_recursive <- "(\\[(?:[^][]++|(?1))*])(*SKIP)(*FAIL)|-"
xx2 <- c("Radio Stations-Listened to Past Week-Toronto [[F[M]]-CFXJ-93.5 (93.5 The Move)]","Total Internet-Time Spent Online-Past 7 Days")
strsplit(xx2, pattern_recursive, perl=TRUE)
# [[1]]
# [1] "Radio Stations"                            
# [2] "Listened to Past Week"                     
# [3] "Toronto [[F[M]]-CFXJ-93.5 (93.5 The Move)]"

# [[2]]
# [1] "Total Internet"    "Time Spent Online" "Past 7 Days"   

答案 2 :(得分:1)

1)gsubfn 假设方括号是平衡的而不是嵌套的,gsubfn定位每个[...]并在这些使用gsub内将短划线转换为感叹号。然后我们将剩余破折号上留下的内容拆分,并用破折号替换感叹号。

正则表达式表示匹配[后跟最短字符串,直到下一个]

library(gsubfn)

s <- strsplit(gsubfn("\\[.*?\\]", ~ gsub("-", "!", x), xx), "-")
lapply(s, gsub, pattern = "!", replacement = "-")

可以使用magrittr管道表示:

library(gsubfn)
library(magrittr)

xx %>%
   gsubfn(pattern = "\\[.*?\\]", replacement = ~ gsub("-", "!", x)) %>%
   strsplit("-") %>%
   lapply(gsub, pattern = "!", replacement = "-")

2)readLines 此替代方案不使用包,不使用strsplit并仅使用简单的固定正则表达式。它还假设平衡的非嵌套方括号。

使用gsub首先使用新行(每行使用换行符和后缀)添加新行。然后对于每个输入字符串,它将结果读入r,对于奇数定位的字符串,用换行替换短划线。最后,它再次将r粘贴在一起并重新读取它,这会在新行(以前是破折号)中将其拆分。

lapply(gsub("\\]", "]\n", gsub("\\[", "\n[", xx)), function(x) {
   r <- readLines(textConnection(x))
   i  <- seq(1, length(r), 2)
   r[i] <- gsub("-", "\n", r[i])
   readLines(textConnection(paste(r, collapse = "")))
})