R grep和精确匹配

6

看起来grep在返回匹配项时具有“贪婪”的特点。假设我有以下数据:

Sources <- c(
                "Coal burning plant",
                "General plant",
                "coalescent plantation",
                "Charcoal burning plant"
        )

Registry <- seq(from = 1100, to = 1103, by = 1)

df <- data.frame(Registry, Sources)

如果我执行grep("(?=.*[Pp]lant)(?=.*[Cc]oal)", df$Sources, perl = TRUE, value = TRUE),它将返回:
"Coal burning plant"     
"coalescent plantation"  
"Charcoal burning plant" 

然而,我只想返回精确匹配,即只有在“coal”和“plant”同时出现的情况下。我不想要“coalescent”,“plantation”等等。因此,为了实现这一点,我只想看到"Coal burning plant"


只需使用 ==,然后如果您想要精确匹配:df$Sources[df$Sources == "Coal burning plant"] - thelatemail
@thelatemail 在这种情况下,那会起作用。但是想象一下,如果我有其他条目,例如“燃煤蒸汽发电厂”,“柴油燃煤发电厂”等,我也想将它们返回。 - sedeh
这确实不是同样的问题。如果将那个问题中的 people.jpg 改为 peoples 并执行 grep 搜索 people,则它会返回包含 "peoples" 的结果。您可以运行以下代码以查看我所说的内容:`x <- c( "imageUploaded,peoples,more,comma,separated,stuff", "imageUploaded", "people.jpg" )xmatches <- intersect( grep("imageUploaded",x,fixed=TRUE), grep("people",x,fixed=TRUE) ) x[xmatches]` - sedeh
对我来说它们看起来非常相似。你想返回包含“coal”和“plant”的匹配项,而他们想返回包含“imageUploaded”和“people.jpg”的匹配项。 - thelatemail
但是假设他们有“people.jpgS”,但只想返回“people.jpg”,那么按照现有的函数,它将无法区分。 - sedeh
2个回答

8

您需要在单词模式周围使用单词边界\b。 单词边界不会消耗任何字符。 它断言一侧有一个单词字符,而另一侧没有。 您可能还想考虑使用内联(?i)修饰符进行不区分大小写的匹配。

grep('(?i)(?=.*\\bplant\\b)(?=.*\\bcoal\\b)', df$Sources, perl=T, value=T)

Working Demo


刚刚检查了一下。这就是当你的团队里有新手时会发生的事情。 - sedeh
我注意到,如果我将“煤油燃烧器”添加到Sources中,然后尝试修改grep函数以查找“煤油”,该函数会崩溃。这是否意味着此函数中不能有两个以上的条件? grep('(?i)(?=.*\\bplant\\b)|(?=.*\\bcoal\\b)|(?=.*\\kerosene\\b)', df$Sources, perl=T, value=T) - sedeh
我用 \b 运行了它,但注意到它似乎没有考虑第三个参数。 - sedeh
当然,我一定是打错了。看起来确实可以有任意数量的条件。再次感谢。 - sedeh

2
如果您总是希望按照“煤”然后是“工厂”的顺序进行排序,那么这应该可以实现。
grep("\\b[Cc]oal\\b.*\\b[Pp]lant\\b", Sources, perl = TRUE, value=T)

在这里,我们添加了一个代表单词边界的\b匹配。您也可以将单词边界添加到您最初的尝试中。

grep("(?=.*\\b[Pp]lant\\b)(?=.*\\b[Cc]oal\\b)", Sources, 
    perl = TRUE, value = TRUE)

第二个选项很可靠,因为顺序并不重要。谢谢。 - sedeh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接