【问题标题】:Extract 2 words in any order以任意顺序提取 2 个单词
【发布时间】:2018-02-03 15:40:09
【问题描述】:

我想按任意顺序提取猫和狗

string1 <- "aasdfadsf cat asdfadsf dog"
string2 <- "asfdadsfads dog asdfasdfadsf cat"

我现在提取的是猫和狗,还有中间的文字

stringr::str_extract(string1, "cat.*dog|dog.*cat"

我希望输出是

cat dog

dog cat

分别用于string1和string2

【问题讨论】:

  • 您确定两者都应该是dog cat 吗?我可以得到cat dog 用于string1 和dog cat 用于string2。或者您想为 string1 获取 dog,为 string2 获取 cat
  • 嗨,Wiktor,是的,我就是这个意思。感谢您的澄清。将相应地编辑 OP
  • 请看我的更新。我已将函数从 str_extract 更改为 str_extract_all 以捕获所有组。

标签: r regex


【解决方案1】:

您可以将sub 与以下 PCRE 正则表达式一起使用:

.*(?|(dog).*(cat)|(cat).*(dog)).*

请参阅regex demo

详情

  • .* - 除换行符之外的任何 0+ 字符(要匹配所有字符,请在模式开始处添加 (?s)
  • (?|(dog).*(cat)|(cat).*(dog)) - 一个分支重置组 (?|...|...) 匹配两个备选方案之一:
    • (dog).*(cat) - 第 1 组捕获 dog,然后是尽可能多的 0+ 个字符,第 2 组捕获 cat
    • | - 或
    • (cat).*(dog) - 第 1 组捕获 cat,然后尽可能多的任何 0+ 字符,第 2 组捕获 dog(在分支重置组中,组 ID 重置为组 + 1 之前的值)
  • .* - 除换行符以外的任何 0+ 个字符

\1 \2 替换模式将第 1 组和第 2 组值插入到结果字符串中(因此结果只是dogcat、一个空格和一个catdog)。

也见an R demo online

x <- c("aasdfadsf cat asdfadsf dog", "asfdadsfads dog asdfasdfadsf cat")
sub(".*(?|(dog).*(cat)|(cat).*(dog)).*", "\\1 \\2", x, perl=TRUE)
## => [1] "cat dog" "dog cat"

若要在不匹配的情况下返回NA,请使用正则表达式匹配特定模式或整个字符串,并将其与gsubfn 一起使用以应用自定义替换逻辑:

> gsubfn("^(?:.*((dog).*(giraffe)|(giraffe).*(dog)).*|.*)$", function(x,a,b,y,z,i) ifelse(nchar(x)>0, paste0(a,y," ",b,z), NA), x)
[1] "NA" "NA"
> gsubfn("^(?:.*((dog).*(cat)|(cat).*(dog)).*|.*)$", function(x,a,b,y,z,i) ifelse(nchar(x)>0, paste0(a,y," ",b,z), NA), x)
[1] "cat dog" "dog cat"

这里,

  • ^ - 字符串的开头 anchor
  • (?:.*((dog).*(cat)|(cat).*(dog)).*|.*) - non-capturing group 匹配以下两种选择中的任何一种: .*((dog).*(cat)|(cat).*(dog)).*:
    • .* - 尽可能多的任何 0+ 个字符
    • ((dog).*(cat)|(cat).*(dog)) - 一个 capturing group 匹配两个选项之一:
      • (dog).*(cat) - dog(第 2 组,分配给 a 变量),任意 0+ 个字符尽可能多,然后 cat(第 3 组,分配给 b 变量)
      • |
      • (cat).*(dog) - dog(第4组,分配给y变量),任意0+个字符尽可能多,然后cat(第5组,分配给z变量)
    • .* - 任何 0+ 字符尽可能多
      • | - 或
      • .* - 任何 0+ 个字符
  • $ - 字符串结尾 anchor

匿名函数中的x代表Group 1的值,这里是“技术”,我们用nchar检查Group 1匹配长度是否不为零,如果不为空,我们替换为自定义逻辑,如果第1组为空,我们用NA替换。

【讨论】:

  • 维克托,非常感谢。唉,我发现了一些东西。如果我的搜索字符串要求现在是“dog”和“giraffe”,“aasdfadsf cat asdfadsf dog”的测试字符串将返回“aasdfadsf cat asdfadsf dog”,而我希望它返回 NA regex101.com/r/fnkDLg/1
  • 谢谢。你能解释一下正则表达式的语法,尤其是“(?:”。另外,函数中的 i 参数的目的是什么?
  • strapply 在这里也可能有用。
【解决方案2】:

我们可以将 包中的str_extract_all 与捕获组一起使用。

string1 <- "aasdfadsf cat asdfadsf dog"
string2 <- "asfdadsfads dog asdfasdfadsf cat"
string3 <- "asfdadsfads asfdadsfadf"

library(stringr)
str_extract_all(c(string1, string2, string3), pattern = "(dog)|(cat)")
# [[1]]
# [1] "cat" "dog"
# 
# [[2]]
# [1] "dog" "cat"
# 
# [[3]]
# character(0)

我们也可以设置simplify = TRUE。输出将是一个矩阵。

str_extract_all(c(string1, string2, string3), pattern = "(dog)|(cat)", simplify = TRUE)
#       [,1]  [,2] 
# [1,] "cat" "dog"
# [2,] "dog" "cat"
# [3,] ""    ""  

【讨论】:

  • 我希望这能达到我想要的效果,因为它非常优雅。但是,如果猫和狗都不在场,我想返回 NA
  • @matsuo_basho 请看我的更新。当没有猫和狗时,函数返回character(0)""取决于simplify = TRUE。您可能希望稍后将它们替换为 NA
  • 我的意思是我希望 NA 为以下字符串返回:“adsfadsf dog asfdadsf”、“asdfadsf cat asdfadsf”
  • 我想你想说的是“狗或猫都不在场”。抱歉,我不是以英语为母语的人,但我认为您没有提供足够的信息来说明您的要求。由于我的输出符合您帖子中您想要的输出,并且您已经找到了您想要的答案,所以我不会修改我的帖子。干杯。
【解决方案3】:

或者,

> regmatches(string1,gregexpr("cat|dog",string1))
[[1]]
[1] "cat" "dog"

> regmatches(string2,gregexpr("cat|dog",string2))
[[1]]
[1] "dog" "cat"

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-18
    • 2017-12-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多