将字符串分隔成行,除非在分隔符集之间

Posted

技术标签:

【中文标题】将字符串分隔成行,除非在分隔符集之间【英文标题】:Separate strings into rows unless between sets of delimiters 【发布时间】:2022-01-07 22:11:15 【问题描述】:

我有带有注释符号的话语:

utt <- c("↑hey girls↑ can I <join yo:u>", "((v: grunts))", "!damn shit! got it", 
"I mean /yeah we saw each other at a party:/↓ the other day"
)

我需要将utt 拆分成单独的单词除非这些单词被某些分隔符包围,包括此类[(/≈↑£&lt;&gt;°!]。我对utts 使用 双负前瞻 做得相当好,其中只有 one 分隔符之间出现这样的字符串;但在分隔符之间存在 多个 这样的字符串时,我无法正确拆分:

library(tidyr)
library(dplyr)
data.frame(utt2) %>%
  separate_rows(utt, sep = "(?!.*[(/≈↑£<>°!].*)\\s(?!.*[)/≈↑£<>°!])")
# A tibble: 9 × 1
  utt2                                        
  <chr>                                       
1 ↑hey girls↑ can I <join yo:u>               
2 ((v: grunts))                               
3 !damn shit!                                 
4 got                                         
5 it                                          
6 I mean /yeah we saw each other at a party:/↓
7 the                                         
8 other                                       
9 day 

预期结果将是:

1 ↑hey girls↑ 
2 can
3 I
4 <join yo:u>               
5 ((v: grunts))                               
6 !damn shit!                                 
7 got                                         
8 it                                          
9 I
10 mean 
11 /yeah we saw each other at a party:/↓
12 the                                         
13 other                                       
14 day 

【问题讨论】:

【参考方案1】:

你可以使用

data.frame(utt2) %>% separate_rows(utt2, sep = "(?:([/≈↓£°!↑]).*?\\1|\\([^()]*\\)|<[^<>]*>)(*SKIP)(*F)|\\s+")

请参阅regex demo。

请注意,在您的情况下,有成对的字符(如()&lt;&gt;)和非成对的字符(如£)。它们需要不同的处理方式反映在模式中。

详情

(?:([/≈↓£°!↑]).*?\\1|\\([^()]*\\)|&lt;[^&lt;&gt;]*&gt;)(*SKIP)(*F) 匹配 ([/≈↓£°!↑]).*?\1| - a /, , , £, °! 字符被捕获到第 1 组,然后除换行符之外的任何零个或多个字符尽可能少(请参阅.*?),然后将相同的字符捕获到第 1 组中 \([^()]*\)| - (,除 () 之外的零个或多个字符,然后是 ) 字符,或 &lt;[^&lt;&gt;]*&gt; - &lt;,除&lt;&gt; 之外的零个或多个字符,然后是&gt; 字符 (*SKIP)(*F) - 跳过匹配的文本并从失败位置重新开始搜索 | - 或 \s+ - 任何其他上下文中的一个或多个空格。

【讨论】:

非常感谢 - 干得好(一如既往)。我仍然对 SKIP 和 FAIL 语法不够熟悉。有没有你推荐的解释网站? @ChrisRuehlemann 见How do (*SKIP) or (*F) work on regex?。如果您仍有疑问,也可以在这里发表评论。 我承认已经阅读了链接的帖子,但我仍然不完全清楚 SKIP 和 FAIL。上述任务使用环视是否也可行? @ChrisRuehlemann 这听起来像是一个新问题 :) 匹配一些不在其他两个模式之间的模式并不是一项简单的正则表达式任务。一般来说,1)如果其他两个模式是相同的单个字符,可以使用像this这样的模式(但效率很低),2)如果模式不同,则需要可变宽度的lookbehind,它将是,比如&lt;&gt;(?&lt;!&lt;[^&lt;&gt;]*)\s(?![^&lt;&gt;]*&gt;)。 PCRE 不支持这一点,ICU 将需要在后视中使用设置的最小值和最大值来限制量词。 3)如果模式不同... @ChrisRuehlemann ...多字符串,上述正则表达式需要经过调和的贪婪令牌。然而,2) 的模式并不精确,当它只是在&lt; 前面而不在&gt; 后面时,它也会避免匹配空格,反之亦然。 \s(?!(?&lt;=&lt;[^&lt;&gt;]*)[^&lt;&gt;]*&gt;) 会更准确,但它是如此神秘。

以上是关于将字符串分隔成行,除非在分隔符集之间的主要内容,如果未能解决你的问题,请参考以下文章

Java Scanner - 除非存在引号,否则用空格分隔?

正则表达式在空格上拆分,除非在引号中

用于根据空格分隔符拆分文本的正则表达式 [重复]

如何在javascript中的两个分隔符之间拆分字符串?

如何将字符串列表连接在一起,每个值之间用逗号分隔?

用子字符串替换后续分隔符之间的字符串