正则表达式,包括和排除R中的某些字符串

jan*_*vak 9 regex r

我正在尝试使用R来解析许多条目.我对我想要的条目有两个要求.我想要包含该单词apple但不包含该单词的所有条目orange.

例如:

  1. 我喜欢苹果
  2. 我真的很喜欢苹果
  3. 我喜欢苹果和橘子

我希望得到第1和第2条.

我怎么能用R来做这件事?

谢谢.

Dav*_*urg 22

能做

temp <- c("I like apples", "I really like apples", "I like apples and oranges")
temp[grepl("apple", temp) & !grepl("orange", temp)]

## [1] "I like apples"      "I really like apples"
Run Code Online (Sandbox Code Playgroud)


hwn*_*wnd 12

使用正则表达式,您可以执行以下操作.

x <- c('I like apples', 'I really like apples', 
       'I like apples and oranges', 'I like oranges and apples',
       'I really like oranges and apples but oranges more')

x[grepl('^((?!.*orange).)*apple.*$', x, perl=TRUE)]
# [1] "I like apples"        "I really like apples"
Run Code Online (Sandbox Code Playgroud)

正则表达式向前看是否除了换行符和没有子串之外没有任何字符orange,如果是这样,那么点将.匹配除换行符之外的任何字符,因为它包含在一个组中,并且重复(0或多次).接下来我们查找apple除了换行符之外的任何字符(0或更多次).最后,线锚的起点和终点到位,以确保消耗输入.


更新:如果性能有问题,您可以使用以下内容.

x[grepl('^(?!.*orange).*$', x, perl=TRUE)]
Run Code Online (Sandbox Code Playgroud)

  • @Arun这确实很棘手.第一个子表达式询问,从第一个字符之前的位置开始,是否有任何字符串后跟字符"apple".如果找到一个,则正则表达式引擎会在第一个字符之前返回到该位置,并开始测试负前瞻断言.第二个子表达式是相对棘手的.它通过在单词中的每个字符间空间检查是否存在:(a)**是**前面的字符但是(b)**不是**字符串"orange"就在前面. (3认同)
  • @Arun - 我有类似的反应.事实上,我一开始看起来确实是错误的,但经过几分钟的尝试,我无法打破它.我很高兴我破解它b/c这种谜题会像顽强的耳虫一样卡在我的脑海中! (3认同)

zx8*_*x81 9

这个正则表达式比其他正则表达式版本更小,更快(见下面的比较).我没有与大卫的双重比较的工具,grepl所以如果有人可以比较grep下面的单个和grepl我们能够知道的双重.必须对成功案例和失败案例进行比较.

^(?!.*orange).*apple.*$
Run Code Online (Sandbox Code Playgroud)
  1. 负向前瞻确保我们没有 orange
  2. 我们只是匹配字符串,只要它包含apple.不需要在那里前瞻.

代码示例

grep("^(?!.*orange).*apple.*$", subject, perl=TRUE, value=TRUE);
Run Code Online (Sandbox Code Playgroud)

速度比较

@hwnd现在已经删除了双重前瞻版本,但根据RegexBuddy,速度差异仍然存在:

  1. 反对I like apples and oranges,引擎需要22步才能失败,而双前瞻版本需要143 ^(?=.*apple)((?!orange).)*$步,而22步^((?!.*orange).)*apple.*$(相等于等待第2点).
  2. 反对I really like apples,引擎需要64步才能成功,而双前瞻版本需要104 ^(?=.*apple)((?!orange).)*$步,而538步需要^((?!.*orange).)*apple.*$.

这些数字由RegexBuddy调试器提供.

  • 是的,这是恕我直言更好,主要是因为它更容易grock. (2认同)