在strpos中使用数组作为查找项

108

当搜索一个字符串时,如何使用strpos查找多个不同的子字符串?例如:

$find_letters = array('a', 'c', 'd');
$string = 'abcdefg';

if(strpos($string, $find_letters) !== false)
{
    echo 'All the letters are found in the string!';
}

因为使用这个时,它不起作用,如果有类似这样的东西就好了。

16个回答

159

@Dave, 这是来自http://www.php.net/manual/en/function.strpos.php#107351的更新片段。

function strposa($haystack, $needles=array(), $offset=0) {
        $chr = array();
        foreach($needles as $needle) {
                $res = strpos($haystack, $needle, $offset);
                if ($res !== false) $chr[$needle] = $res;
        }
        if(empty($chr)) return false;
        return min($chr);
}

如何使用:

$string = 'Whis string contains word "cheese" and "tea".';
$array  = array('burger', 'melon', 'cheese', 'milk');

if (strposa($string, $array, 1)) {
    echo 'true';
} else {
    echo 'false';
}

因为array包含"cheese",所以将返回true

更新:改进了代码以在找到第一个针时停止搜索:

function strposa(string $haystack, array $needles, int $offset = 0): bool 
{
    foreach($needles as $needle) {
        if(strpos($haystack, $needle, $offset) !== false) {
            return true; // stop on first true result
        }
    }

    return false;
}
$string = 'This string contains word "cheese" and "tea".';
$array  = ['burger', 'melon', 'cheese', 'milk'];
var_dump(strposa($string, $array)); // will return true, since "cheese" has been found

1
@Arnaud,你建议采用什么实现方式? - Binyamin
5
我不确定,但也许我们可以从$offset开始在字符串中前进,并在找到第一个针之后停止。想象一下一个充满“a”的大文本。取 $needles = [a, b]。你的函数 strposa 将遍历整个文本,但这并不是必要的!我表达清楚了吗? - Arnaud
这并不是我想要表达的,因为使用你的新函数$needles = [b, a]仍然存在问题,而且该函数不再返回第一次出现的位置。让我再解释一下。假设字符串是“ABCDEF”,针是C和F。我们可以遍历字符串:A,B... C!我们检测到C,所以我们停在这里,我们可以返回针的第一个出现位置,即2。它可以处理多个字符的字符串,但我还没有考虑确切的实现方式。 - Arnaud
@Arnaud,这就是它现在的确切工作方式。foreach将在数组“cheese”上停止,并且不会检查“milk”,因为已经找到了一个有效结果。我也尝试过使用if(!empty($res)) break;的实现方式,但是发现它也可以正常工作。通过在foreach中添加$res = strpos($haystack, $query, 1); if(!empty($res)) break;来检查它。 - Binyamin
1
我通过更改代码 foreach($needle as $k => $query) { if(strpos($haystack, $query, $offset) !== false) return $k; } 来改进它,以便返回匹配项的键以供进一步处理。 - James Cameron
显示剩余6条评论

91

str_replace更快。

$find_letters = array('a', 'c', 'd');
$string = 'abcdefg';
$match = (str_replace($find_letters, '', $string) != $string);

语法错误:第3行有一个多余的闭括号(由于> 6个字符的编辑要求,我无法直接在上面的代码中进行更正;) - richey
1
抱歉,那是随口说的。现在已经修复了。感谢提醒! - Leon
13
最好的解决方案之一! - andys
这可能对于问题中所要求的字母数组更快。但如果是短语数组,那么我认为strpos会更快。 - Sadee

20
下面的代码不仅展示了如何实现,还将其放在一个易于使用的函数中。这段代码是由“jesda”编写的。(我在网上找到的) PHP 代码:
<?php
/* strpos that takes an array of values to match against a string
 * note the stupid argument order (to match strpos)
 */
function strpos_arr($haystack, $needle) {
    if(!is_array($needle)) $needle = array($needle);
    foreach($needle as $what) {
        if(($pos = strpos($haystack, $what))!==false) return $pos;
    }
    return false;
}
?>

使用方法:

$needle = array('something','nothing');
$haystack = "This is something";
echo strpos_arr($haystack, $needle); // Will echo True

$haystack = "This isn't anything";
echo strpos_arr($haystack, $needle); // Will echo False 

我认为这只返回它找到的第一个位置。有什么建议可以调整它以返回在“干草堆”中每个“针”的位置? - Chaya Cooper

9
提供的例子是一个"例子"还是确切符合您所需的?这里有很多答案,其中有很多混杂在一起,而我也不理解被接受那个答案的复杂性。
为了找出字符串中是否存在"任何"针头数组内容,并"快速地"返回true或false:
$string = 'abcdefg';

if(str_replace(array('a', 'c', 'd'), '', $string) != $string){
    echo 'at least one of the needles where found';
};

如果是这样,请给@Leon点个赞。
要确定字符串中是否存在数组的所有针值,就像你举的“例如”一样,必须同时存在所有三个值'a','b'和'c'。

echo 'All the letters are found in the string!';

许多答案都超出了这个背景,但我怀疑问题的意图是否已得到解决。例如,被接受的答案是一个针。
$array  = array('burger', 'melon', 'cheese', 'milk');

如果字符串中必须包含所有这些单词,该怎么办呢?那么你可以在这个页面上尝试一些"不被接受的答案"

这个方法完美适合我,因为我需要查找数组中包含的子字符串。我因此避免了编写类似于“%$string%”的SQL命令。 - Maurice Elagu

6
你可以遍历数组并在 strpos 返回 false 时设置一个“标志”值。
$flag = false;
foreach ($find_letters as $letter)
{
    if (strpos($string, $letter) !== false)
    {
        $flag = true;
    }
}

然后检查$flag的值。


7
应该是!== false而不是!== flase - Joe Huang
它应该是!==false。除非你在将标志设置为true后立即退出。然后必须将标志解释为警告,表示针不在干草堆中。这意味着您试图实现的是检查所有针是否都在干草堆中,而这并不是问题所在。所以..没错。! == false - Kevin Gagnon

5

如果您只想检查某些字符是否实际存在于字符串中,请使用strtok

$string = 'abcdefg';
if (strtok($string, 'acd') === $string) {
    // not found
} else {
    // found
}

真是一个令人惊叹的答案——执行速度比多次使用strpos()更快,例如如果(strpos($string, "a") !== false && strpos($string, "c") !== false && strpos($string, "d") !== false)。 - The One and Only ChemistryBlob

4

这个表达式用于搜索所有字母:

count(array_filter( 
    array_map("strpos", array_fill(0, count($letters), $str), $letters),
"is_int")) == count($letters)

4
你可以尝试这个:
function in_array_strpos($word, $array){

foreach($array as $a){

    if (strpos($word,$a) !== false) {
        return true;
    }
}

return false;
}

1
这是我的方法。迭代字符串中的字符,直到找到匹配项。在较大的针数组上,此方法将优于已接受的答案,因为它不需要检查每个针来确定是否已找到匹配项。
function strpos_array($haystack, $needles = [], $offset = 0) {
    for ($i = $offset, $len = strlen($haystack); $i < $len; $i++){
        if (in_array($haystack[$i],$needles)) {
            return $i;
        }
    }
    return false;
}

我将这个与被接受的答案进行了基准测试,并且当使用一个超过7个$needles的数组时,速度会显著地更快。


1
如果我只想查找堆栈中是否存在任何针,我使用可重用函数。
function strposar($arrayOfNeedles, $haystack){
  if (count(array_filter($arrayOfNeedles, function($needle) use($haystack){
     return strpos($haystack, $needle) !== false;
   })) > 0){
    return true;
  } else {
    return false;
  }
}

strposar($arrayOfNeedles, $haystack); //returns true/false

或者lambda函数
  if (count(array_filter($arrayOfNeedles, function($needle) use($haystack){
     return strpos($haystack, $needle) !== false;
   })) > 0){
     //found so do this
   } else {
     //not found do this instead
   }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接