【问题标题】:php preg_match_all() 70 times for each word | Api endpoint | performancephp preg_match_all() 每个单词 70 次 | API 端点 |表现
【发布时间】:2020-08-19 13:09:49
【问题描述】:

我有一个 70 个单词的列表。此列表用于检查用户输入。用户输入是文本,平均有 30-100 个单词。如果我列表中的单词之一在文本中,则删除用户文本,否则允许。在大多数情况下它是被允许的,所以它会遍历所有的单词。

检查单词是否在我使用的用户文本中:

$susWords = SuspiciousWord::where('checked', true)->get();

$foundSusWord = false;
foreach ($susWords as $word) {
    if (preg_match_all("/" . $word->word . "/i", $user->flirttext)) {
        $foundSusWord = true;     
    break;
    }
} 

在正则表达式和性能方面,我不是专家。性能可能是这里的问题吗?

【问题讨论】:

  • 为什么是正则表达式而不是stripos() !== false

标签: php regex performance


【解决方案1】:
  1. 使用stripos($user->flirttext, $word->word) !== false 更快地检查,因为不需要正则表达式。
  2. 使用preg_match('/\b(' . implode('|', array_column($susWords, 'word')) . ')\b/', $user->flirttext) 一次检查所有单词

【讨论】:

  • 以下哪个更快?我的两个词是模式,这里是一个例子\sig\s。我可以对所有非模式词使用第一种方法,对模式使用正则表达式方法。
  • @Roman \sig\s\big\b 覆盖。正则表达式总是比简单的字符串操作慢
  • 是的,我明白了,但是我应该将第二个示例用于所有单词还是将其拆分为两个函数。值得吗?我只有 2 个带模式的单词
  • 第二个例子有错误,如果它是字符串的一部分,它将找不到单词,例如如果用户输入是sexy,则不会找到单词sex,这很糟糕,我的原来的正则表达式已经找到了。
  • 既然你是通过|加入的,那么制作两个列表没有意义
【解决方案2】:

你可以使用strpos()

https://www.php.net/manual/en/function.strpos.php

比正则表达式高效得多。

这里有一些基准: https://stackoverflow.com/a/6433599/9470935

【讨论】:

    【解决方案3】:

    编辑:正如@Justinas 所指出的,如果文本中只有标点符号,这种方法并不是很好。根本不应该在这种情况下使用。留在这里作为参考

    您还可以使用 array_intersect 来避免循环:

    $wordlist = explode(' ', $user->flirttext));
    if (count(array_intersect($susWords, $wordlist)) > 0) {
        // found a bad word, do something
    }
    

    doc here

    【讨论】:

    • 如果你搜索hello并且用户输入了foo bar hello.???怎么办?
    • 你是对的,确实,它需要更多的解析,可能会丢失一些其他字符,因此不是一个很好的方法。我会把答案留给其他人看,不会犯同样的错误,而是编辑以警告人们
    猜你喜欢
    • 2014-06-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多