在PHP中搜索单个字符串中的不同字符串数组

时间:2009-09-25 20:06:05

标签: php regex arrays search

我有一个字符串数组,我想尝试匹配到普通字符串的末尾。我不确定在PHP中执行此操作的最佳方法。

这是我想做的事情:

  

示例:

     

输入:abcde

     

搜索数组:er,wr,de

     

匹配:de

我的第一个想法是编写一个遍历数组的循环,并通过在每个字符串的末尾添加“\ b”来制作正则表达式,然后检查它是否在输入字符串中找到。虽然这可行,但循环整个数组似乎效率低下。我被告知正则表达式在PHP中很慢,并且不想实现会让我走错路的东西。

有没有更好的方法来查看我的数组中的某个字符串是否出现在输入字符串的末尾?

preg_filter()函数看起来似乎可以完成这项工作但是适用于PHP 5.3+而且我仍然坚持5.2.11稳定。

4 个答案:

答案 0 :(得分:5)

对于这么简单的事情,你不需要正则表达式。您可以循环遍历数组,并使用strpos查看索引是否为长度(输入) - 长度(测试)。如果搜索数组中的每个条目始终具有恒定长度,您还可以通过从输入中删除结尾,然后将其与数组中的每个项目进行比较来加快速度。

您无法避免遍历整个数组,因为在最糟糕的一般情况下,匹配的项目将位于数组的末尾。但是,除非阵列很大,否则我不会过分担心性能 - 它会比你想象的要快得多。

答案 1 :(得分:1)

虽然编译正则表达式需要一些时间,但我不会轻易放弃使用pcre。除非你找到一个需要多针的比较功能,你需要一个针的循环并执行循环+调用每个针的比较功能也需要时间。

让我们拿一个测试脚本从php.net中获取所有函数名称并查找某些结尾。这只是一个特殊的脚本,但我想无论你使用哪个strcmp-ish函数+循环,它都会比简单的pcre模式慢(在这种情况下)。

count($hs)=5549
pcre: 4.377925157547 s
substr_compare: 7.951938867569 s
identical results: bool(true)

这是搜索九种不同模式时的结果。如果只有两个('yadda','ge')两种方法花费的时间相同。

随意批评测试脚本(合成测试中总是出现错误,除了自己以外,每个人都很明显吗?;-))

<?php
/* get the test data
All the function names from php.net
*/
$doc = new DOMDocument;
$doc->loadhtmlfile('http://docs.php.net/quickref.php');
$xpath = new DOMXPath($doc);
$hs = array();
foreach( $xpath->query('//a') as $a ) {
  $hs[] = $a->textContent;
}
echo 'count($hs)=', count($hs), "\n";
// should find:
// ge, e.g. imagick_adaptiveblurimage
// ing, e.g. m_setblocking
// name, e.g. basename 
// ions, e.g. assert_options
$ns = array('yadda', 'ge', 'foo', 'ing', 'bar', 'name', 'abcd', 'ions', 'baz');
sleep(1);

/* test 1: pcre */
$start = microtime(true);
for($run=0; $run<100; $run++) {
  $matchesA = array();
  $pattern = '/(?:' . join('|', $ns) . ')$/';
  foreach($hs as $haystack) {
    if ( preg_match($pattern, $haystack, $m) ) {
      @$matchesA[$m[0]]+= 1;
    }
  }
}
echo "pcre: ", microtime(true)-$start, " s\n";
flush();
sleep(1);

/* test 2: loop + substr_compare */
$start = microtime(true);
for($run=0; $run<100; $run++) {
  $matchesB = array();
  foreach( $hs as $haystack ) {
    $hlen = strlen($haystack);
    foreach( $ns as $needle ) {
      $nlen = strlen($needle);
      if ( $hlen >= $nlen && 0===substr_compare($haystack, $needle, -$nlen) ) {
        @$matchesB[$needle]+= 1;
      }
    }
  }
}
echo "substr_compare: ", microtime(true)-$start, " s\n";
echo 'identical results: '; var_dump($matchesA===$matchesB);

答案 2 :(得分:0)

我可能会倒退;

如果您的字符串结尾列表是固定的或很少变化, 我会从预处理开始,以便与之匹配, 然后抓住你的字符串的结尾,看它是否匹配!

示例代码:

<?php

// Test whether string ends in predetermined list of suffixes
// Input: string to test
// Output: if matching suffix found, returns suffix as string, else boolean false
function findMatch($str) {
    $matchTo = array(
        2 => array( 'ge' => true, 'de' => true ),
        3 => array( 'foo' => true, 'bar' => true, 'baz' => true ),
        4 => array( 'abcd' => true, 'efgh' => true )
    );

    foreach($matchTo as $length => $list) {
        $end = substr($str, -$length);

        if (isset($list[$end]))
            return $end;
    }

    return $false;
}

?>

答案 3 :(得分:0)

这可能是一种矫枉过正,但您可以尝试以下方法。 为搜索数组的每个条目创建一个哈希值,并将它们作为键存储在数组中(这将是您的查找数组)。

然后从输入字符串的末尾开始一个字符(e,de,cde等),并在每次迭代时计算子字符串的哈希值。如果你的查找数组中有一个哈希,你就有很多。