PHP检查字符串中的单词而不使用foreach循环

时间:2014-06-10 01:43:50

标签: php loops foreach

我有以下代码:

$wordsArray = ...
foreach ( $wordsArray as $word ) 

    if ( strpos( $string, $word ) !== FALSE ) { 
         echo "Word found! Handle this a certain way" }
    }

}

不幸的是,有这么大的单词数组(可能接近100),循环太慢了,特别是当我向这个函数传递数千个字符串,并运行这个foreach循环数千次。我如何加快这个过程,或重构我的代码,我不需要循环我的单词数组,而是利用字符串本身并检查它是否在我的数组中找到它的任何子字符串?我需要让这部分代码更有效率。

此外,更难的是每个字符串都没有空格。相反,请采用以下示例:

  

传递字符串:“Hereissomerandomsentence”

     

单词数组:('some','are','the');

由于“some”,我的脚本将返回Word Found,但我想找到一种更快的方法来执行此操作。

3 个答案:

答案 0 :(得分:2)

不管你喜欢与否,都会涉及到一些循环,但是当你切换到正则表达式时,可能会进行一些优化:

$re = '/(?:' . join('|', array_map(function($word) {
    return preg_quote($word, '/');
}, $wordsArray)) . ')/';

if (preg_match_all($re, $string, $matches)) {
    // hurray!
    print_r($matches[0]);
}

答案 1 :(得分:1)

容易但也不容易。以下是一些使用preg_match_all和简单正则表达式作为示例的代码:

// Set the string.
$string = 'Hereissomerandomsentence';

// Set the words array.
$wordsArray = array('some', 'are', 'the');

// Set the regex pattern.
$regex_pattern = '/(?:' . implode('|', $wordsArray) . ')/i';

// Run a regex to get the value between the link tags.
preg_match_all($regex_pattern, $string, $matches);

// Return the results.
echo '<pre>';
print_r($matches);
echo '</pre>';

以下是结果:

Array
(
    [0] => Array
        (
            [0] => some
        )

)

但是当我说这不容易时,缺少空格可能会导致thenthe匹配等等。请记住,计算机无法读取。这都是模式逻辑。因此,如果我将thenare添加到示例字符串中,如下所示:

// Set the string.
$string = 'Hereissomerandomsentencethenhereweare';

结果反映了the中的then被提取:

Array
(
    [0] => Array
        (
            [0] => some
            [1] => the
            [2] => are
        )

)

编辑:原始海报在评论中提出了一个公平但复杂的问题:

  

如果我只想要一个单词前面有另一个单词,该怎么办?对于   例如,使用相同的测试字符串,您如何更改正则表达式   仅在some之前包含isthe之前包含then   areare前面有&#39;我们&#39;?所以对你的例子来说   输出只会是某些&#39;和$string = 'Hereissomerandomsentencethenhereweare'; // Set the regex pattern. $regex_pattern = '/(?<=is)some|(?<=then)the|(?<=we)are/i'; // Run a regex to get the value between the link tags. preg_match_all($regex_pattern, $string, $matches); // Return the results. echo '<pre>'; print_r($matches); echo '</pre>';

您要求做的事情很复杂,但使用“Lookarounds”as explained on this site可行:

以下是使用上述代码的示例:

Array
(
    [0] => Array
        (
            [0] => some
            [1] => are
        )

)

结果将如您所愿:

/(?<=is)some|(?<=then)the|(?<=we)are/i

这是对正则表达式/的解释:

  • 开头和结尾的斜杠(|)只是分隔符。
  • OR字符只是条件之间的OR
  • 现在(?<=is)some条件之间存在的是模式。

现在让我们以第一个(?<=[word in here])为例。

  • is是一个“Lookbehind”,意思是:只有在此处带有单词的前面,才会捕获后面的单词。在这种情况下,some
  • 接下来的单词是some
  • 所以这一切都增加到:如果前面有is,则只匹配the。然后then仅在前面有are。然后we仅在前面加{{1}}。

现在知道这里有一个模式可能会创建一个多维数组,可以设置单词的逻辑,只有在前面有另一个单词时才能检查。然后循环,以创建一堆正则表达式。但这是一项艰巨的任务。

但至少现在你知道这个任务的正则表达式的基础知识了!

答案 2 :(得分:1)

  • 对包含可能的潜在从属词的数组进行排序 在$ string中找到。
  • 考虑一个由起始字母组织的多维数组;制作潜在匹配词典,而不是使用大规模的未排序数组。
  • 通过将$ string的副本剪切为单个字符来解析$ string的副本。
  • 知道在什么索引处可以找到哪些字符。
  • 将这些字符放入一个集合中,以便您只使用唯一字符 字符。
  • 检查每个独特的角色。如果是从属词 数组不以其中一个唯一字符开头,或者保持 那些字符,然后可以作为潜在的匹配被丢弃。

使用这些想法,您可以减少所需的比较次数。通过减小潜在解决方案集的大小,您可以加快匹配速度。

为了使这些减少技术显示其价值,潜在匹配的数组将需要很大。也就是说,您节省的处理时间需要超过削减不太可能的匹配所花费的处理时间。

在提供的示例字符串中,字母表的使用方式如下: a2 b c 1 d 1 e 11 F G 3 我1 Ĵ ķ 升 m 2 n 4 o 2 p q 4 3 t 2 ü v w 1 X ÿ ž。

因此,根本没有使用13个字母的26个字母。一半的字母没有出现。此外,e的发生率几乎是其竞争对手的3倍:h,n和r。这意味着根据他们的开始方式消除下属单词可能会减少时间。