如何加速R中的正则表达式搜索?

时间:2016-06-20 11:07:34

标签: regex r regex-negation

我有一个代码

matrix<-outer(df$text, df1$regexp, str_count)

df超过1000个文本,每个约1500个符号 和df1有500个正则表达式否定表达式,如

(?<!(no|not|n`t|n’t|neither|never|no one|nobody|none|nor|nothing|nowhere|hardly|barely|scarcely|unlikely|seldom|rarely))[ ][aA][bB][aA][nN][dD][oO][nN]

所以我的代码运行了一个多小时

如何加速我的代码?

示例:

library(stringr)
df<-data.frame(names=c("text1","text2"), text=c("one two three four five","six seven eight nine ten"))
regex<-data.frame(names=c("1","2"), regexp=c("(?<!(no|not))[ ][oO][nN][eE]","(?<!(no|not))[ ][fF][iI][vV][eE]"))
matrix<-outer(df$text, as.character(regex$regexp), str_count)

我尝试与

并行运行代码
library(stringr)
library(parallel)
no_cores <- detectCores() - 1
df<-data.frame(names=c("text1","text2"), text=c("one two three four five","six seven eight nine ten"))
regex<-data.frame(names=c("1","2"), regexp=c("(?<!(no|not))[ ][oO][nN][eE]","(?<!(no|not))[ ][fF][iI][vV][eE]"))
cl <- makeCluster(no_cores)
matrix<-parSapply(cl,regex$regexp, str_count, string=df$text)
stopCluster(cl)

现在我的4核PC上编码速度提高了40%

我改变了像Wiktor推荐的所有正则表达式,使用代码运行速度比使用旧正则表达式的并行代码快25%左右

(?<!n(?:[`’]t|e(?:ither|ver)|o(?:t| one|body|ne|r|thing|where){0,1})|hardly|barely|scarcely|unlikely|seldom|rarely)[ ][aA][bB][aA][nN][dD][oO][nN]

2 个答案:

答案 0 :(得分:1)

stringr 中使用的正则表达式风格是ICU(因此,无法在regex101.com上测试它是否有效)并且这种风格不需要完全固定宽度的外观。在一些简单的情况下,它确实支持限制量词以及常规<select name="comuna" class="form-control" tabindex=8 id="comuna_select" required> <option disabled selected style="font-color: #ccc;">Comuna</option> <option value="Cachapoal/Codegua">Cachapoal / Codegua</option> <option value="Cachapoal/Coinco">Cachapoal / Coinco</option> </select> <input id="datepicker" type="text" name="fecha" class="form-control" tabindex=9 placeholder="Click para seleccionar fecha" required/> *(尽管后两者更像是一个错误,而不是一个功能,可能会在以后修复)。

所以,你的正则表达式运行缓慢,因为几个交替分支以相同的子串开始。这造成了过多的回溯。您需要确保每个分支在同一个位置不匹配。

使用

+

答案 1 :(得分:0)

预先正确创建数据(字符而不是因子)

df <- data.frame(names=c("text1","text2"),
               text=c("one two three four five",
                      "six seven eight nine ten"),
               stringsAsFactors=FALSE)

regex <- data.frame(names=c("1","2"), 
                    regexp=c("(?<!(no|not))[ ][oO][nN][eE]",
                             "(?<!(no|not))[ ][fF][iI][vV][eE]"),
                    stringsAsFactors=FALSE)

R函数通常被矢量化&#39;,这意味着每个正则表达式都可以应用于字符串向量

str_count(pattern=regex$regex[1], string=df$text)

sapply(regex$regex, str_count, string=df$text)

例如,

> sapply(regex$regex, str_count, string=df$text)
     (?<!(no|not))[ ][oO][nN][eE] (?<!(no|not))[ ][fF][iI][vV][eE]
[1,]                            0                                1
[2,]                            0                                0

可能这会在两个维度上线性扩展,但随着outer()的增加,使用length(df$text)的速度要快得多。