在字符串中搜索模式

时间:2012-11-12 18:38:51

标签: php algorithm search pattern-matching

在字符串中进行模式搜索。

例如。

$string = "111111110000";
FindOut($string);

函数应返回0

function FindOut($str){    
    $items =  str_split($str, 3);    
    print_r($items);
}

5 个答案:

答案 0 :(得分:2)

如果我理解正确,你的问题归结为找出一个字符串中是否有3个字符的子字符串两次没有重叠。如果确实如此,这将使您获得第一次出现的位置:

function findPattern($string, $minlen=3) {
    $max = strlen($string)-$minlen;
    for($i=0;$i<=$max;$i++) {
        $pattern = substr($string,$i,$minlen);
        if(substr_count($string,$pattern)>1)
            return $i;
    }
    return false;
}

或者我在这里遗漏了什么?

答案 1 :(得分:1)

您在这里可以通过滑动窗口在概念上解决问题。对于您的示例,您有一个大小为3的滑动窗口。

对于字符串中的每个字符,您将当前字符的子字符串和接下来的两个字符作为当前模式。然后,将窗口向上滑动一个位置,并检查字符串的其余部分是否具有当前模式包含的内容。如果是,则返回当前索引。如果没有,请重复。

示例:

1010101101
|-|

所以,pattern = 101。现在,我们将滑动窗口推进一个字符:

1010101101
 |-|

查看字符串的其余部分是否有101,检查每个3个字符的组合。

从概念上讲,这应该是解决此问题所需的全部内容。

编辑:我真的不喜欢当人们只是要求代码时,但由于这似乎是一个有趣的问题,这里是我对上述算法的实现,它允许窗口大小要改变(而不是固定为3,该功能只是简单测试并省略明显的错误检查):

function findPattern( $str, $window_size = 3) {
    // Start the index at 0 (beginning of the string)
    $i = 0;

    // while( (the current pattern in the window) is not empty / false)
    while( ($current_pattern = substr( $str, $i, $window_size)) != false) {
        $possible_matches = array();

        // Get the combination of all possible matches from the remainder of the string
        for( $j = 0; $j < $window_size; $j++) {
            $possible_matches = array_merge( $possible_matches, str_split( substr( $str, $i + 1 + $j), $window_size));
        }

        // If the current pattern is in the possible matches, we found a duplicate, return the index of the first occurrence
        if( in_array( $current_pattern, $possible_matches)) {
            return $i;
        }

        // Otherwise, increment $i and grab a new window
        $i++;
    }
    // No duplicates were found, return -1
    return -1;
}

应该注意的是,这当然不是最有效的算法或实现,但它应该有助于澄清问题,并提供一个直接的例子来解决它。

答案 2 :(得分:1)

看起来你更想用一个子字符串函数来走动并检查每三个字符而不只是将它分成3个

function fp($s, $len = 3){
  $max = strlen($s) - $len; //borrowed from lafor as it was a terrible oversight by me
  $parts = array();

  for($i=0; $i < $max; $i++){
    $three = substr($s, $i, $len);
    if(array_key_exists("$three",$parts)){
          return $parts["$three"];  
    //if we've already seen it before then this is the first duplicate, we can return it
    }
    else{
      $parts["$three"] = i; //save the index of the starting position.
    }
  }

  return false; //if we get this far then we didn't find any duplicate strings
}

答案 3 :(得分:0)

根据str_split documentationstr_split上的"1010101101"调用将导致:

Array(
  [0] => 101
  [1] => 010
  [2] => 110
  [3] => 1
}

这些都不会相互匹配。

你需要查看每个3长的字符串切片(从索引0开始,然后索引1,依此类推)。

我建议您查看substr,您可以这样使用:

substr($input_string, $index, $length)

它会从$input_string开始$index得到$length的部分{{1}}。

答案 4 :(得分:0)

快速而肮脏地实施此类模式搜索:

function findPattern($string){
    $matches = 0;
    $substrStart = 0;

    while($matches < 2 && $substrStart+ 3 < strlen($string) && $pattern = substr($string, $substrStart++, 3)){
        $matches = substr_count($string,$pattern);
    }

    if($matches < 2){
        return null;
    }
    return $substrStart-1;