Usando uma matriz como agulhas em strpos

89

Como você usa o strpospara uma série de agulhas ao pesquisar uma string? Por exemplo:

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

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

Porque ao usar isso não funcionaria, seria bom se houvesse algo assim

MacMac
fonte

Respostas:

134

@Dave um snippet atualizado de 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);
}

Como usar:

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

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

vai voltar true, por causa de array "cheese".

Atualização: Código aprimorado com parada quando a primeira das agulhas é encontrada:

function strposa($haystack, $needle, $offset=0) {
    if(!is_array($needle)) $needle = array($needle);
    foreach($needle as $query) {
        if(strpos($haystack, $query, $offset) !== false) return true; // stop on first true result
    }
    return false;
}
$string = 'Whis string contains word "cheese" and "tea".';
$array  = array('burger', 'melon', 'cheese', 'milk');
var_dump(strposa($string, $array)); // will return true, since "cheese" has been found
Binyamin
fonte
1
@Arnaud, qual é o seu implemento sugerido?
Binyamin de
5
Não tenho certeza, mas talvez possamos avançar na string de $ offset e parar quando a primeira das agulhas for encontrada. Pense em um grande texto cheio de "a". Pegue $ needles = [a, b]. Sua função strposapercorrerá todo o texto, mas não é necessário! Eu sou compreensível?
Arnaud de
Obrigado @Arnaud pela sugestão de recurso! Concordo totalmente com a importância da sua sugestão e atualizei minha resposta com um exemplo de código aprimorado.
Binyamin de
Isso não é exatamente o que eu queria dizer, porque com sua nova função $ needles = [b, a] ainda tem um problema e, além disso, a função não retorna mais a posição da primeira ocorrência. Deixe-me explicar um pouco mais. Suponha que a string seja "ABCDEF" e as agulhas sejam C e F. O que poderíamos fazer é percorrer a string: A, B ... C! Detectamos C, então paramos aqui e podemos retornar a posição da primeira ocorrência de uma agulha, que é 2. Ela poderia funcionar com mais do que strings de um único caractere, mas não pensei sobre a implementação exata.
Arnaud de
1
Eu melhorei o código mudando foreach($needle as $k => $query) { if(strpos($haystack, $query, $offset) !== false) return $k; }, então ele retorna a chave do item correspondente para tratamento posterior.
James Cameron
51

str_replace é consideravelmente mais rápido.

$find_letters = array('a', 'c', 'd');
$string = 'abcdefg';
$match = (str_replace($find_letters, '', $string) != $string);
Leon
fonte
erro de sintaxe: 1 colchete de fechamento muito na linha # 3 (não consegui corrigi-lo diretamente no código acima devido ao requisito de edição de> 6 caracteres;))
richey
1
Ops, isso foi improvisado. Corrigido agora. Viva o alerta!
Leão
6
uma das maiores soluções!
Andy
18

O código abaixo não apenas mostra como fazer isso, mas também o coloca em uma função fácil de usar no futuro. Foi escrito por "jesda". (Eu encontrei online)

Código 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;
}
?>

Uso:

$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 
Dave
fonte
Eu acredito que isso só retorna a 1ª posição que encontra. Alguma sugestão de como ajustá-lo para retornar a posição de cada agulha no palheiro?
Chaya Cooper
7

Você pode iterar pela matriz e definir um valor "sinalizador" se strposretornar false.

$flag = false;
foreach ($find_letters as $letter)
{
    if (strpos($string, $letter) === false)
    {
        $flag = true;
    }
}

Em seguida, verifique o valor de $flag.

Evan Mulawski
fonte
6
não deveria ser !== flase?
Joe Huang
Deve ser! == false. A menos que você interrompa logo após definir seu sinalizador como verdadeiro. E então teria que interpretar a bandeira como um Aviso de que uma agulha não está no palheiro. Isso significa que o que você está tentando fazer é verificar se todas as suas agulhas estão no palheiro. Essa não é a questão. Então sim. ! == false
Kevin Gagnon
5

Se você deseja apenas verificar se certos caracteres estão realmente na string ou não, use strtok :

$string = 'abcdefg';
if (strtok($string, 'acd') === $string) {
    // not found
} else {
    // found
}
netcoder
fonte
Resposta incrível - execução MUITO mais rápida do que vários strpos (), por exemplo, if (strpos ($ string, "a")! == false && strpos ($ string, "c")! == false && strpos ($ string, " d ")! == false)
The One and Only ChemistryBlob
5

A questão: o exemplo fornecido é apenas um "exemplo" ou é exatamente o que você está procurando? Existem muitas respostas misturadas aqui, e eu não entendo a complexidade da aceita.

Para descobrir se ALGUM conteúdo da matriz de agulhas existe na string e retornar rapidamente verdadeiro ou falso:

$string = 'abcdefg';

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

Em caso afirmativo, dê crédito a @Leon por isso.

Para descobrir se TODOS os valores da matriz de agulhas existem na string, como neste caso, todos os três 'a', 'b'e 'c'DEVEM estar presentes, como você mencionou como seu "por exemplo"

echo 'Todas as letras são encontradas na string!';

Muitas respostas aqui estão fora desse contexto, mas duvido que a intenção da pergunta que você marcou como resolvida. Por exemplo, a resposta aceita é uma agulha de

$array  = array('burger', 'melon', 'cheese', 'milk');

E se todas essas palavras DEVEM ser encontradas na string?

Então você experimenta alguns "not accepted answers"nesta página.

Jonas Lundman
fonte
Isso funcionou perfeitamente para mim, já que estava procurando que meu array continha sub-strings. Fui salvo de escrever um comando sql como "% $ string%"
Maurice Elagu
4

Esta expressão procura todas as letras:

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

Você pode tentar isto:

function in_array_strpos($word, $array){

foreach($array as $a){

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

return false;
}
Rajnesh Nadan
fonte
1

Você também pode tentar usar strpbrk () para a negação (nenhuma das letras foi encontrada):

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

if(strpbrk($string, implode($find_letters)) === false)
{
    echo 'None of these letters are found in the string!';
}
O Único ChemistryBlob
fonte
1

Esta é a minha abordagem. Repita os caracteres da string até que uma correspondência seja encontrada. Em uma gama maior de agulhas, isso superará a resposta aceita porque não precisa verificar todas as agulhas para determinar se uma correspondência foi encontrada.

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;
}

Eu comparei isso com a resposta aceita e com um array de mais de 7 $needlesisso foi dramaticamente mais rápido.

Billynoah
fonte
0

Com o seguinte código:

$flag = true;
foreach($find_letters as $letter)
    if(false===strpos($string, $letter)) {
        $flag = false; 
        break;
    }

Em seguida, verifique o valor de $flag. Se for true, todas as letras foram encontradas. Se não, é false.

hakre
fonte
0

Estou escrevendo uma nova resposta que espero ajudar qualquer pessoa que esteja procurando algo semelhante ao que eu sou.

Isso funciona no caso de "Eu tenho várias agulhas e estou tentando usá-las para localizar um fio isolado". e esta é a pergunta que eu encontrei para descobrir isso.

    $i = 0;
    $found = array();
    while ($i < count($needle)) {
        $x = 0;
        while ($x < count($haystack)) {
            if (strpos($haystack[$x], $needle[$i]) !== false) {
                array_push($found, $haystack[$x]);
            }
            $x++;
        }
        $i++;
    }

    $found = array_count_values($found);

O array $foundconterá uma lista de todas as agulhas correspondentes, o item do array com o valor de contagem mais alto será a (s) string (s) que você está procurando, você pode conseguir isso com:

print_r(array_search(max($found), $found));
ConorReidd
fonte
0

Responder a @binyamin e @Timo .. (não há pontos suficientes para adicionar um comentário ..) mas o resultado não contém a posição ..
O código abaixo retornará a posição real do primeiro elemento que é o que strpos se destina a Faz. Isso é útil se você espera encontrar exatamente 1 correspondência. Se espera encontrar várias correspondências, a posição da primeira encontrada pode não ter significado.

function strposa($haystack, $needle, $offset=0) {
    if(!is_array($needle)) $needle = array($needle);
    foreach($needle as $query) {
      $res=strpos($haystack, $query, $offset);
      if($res !== false) return $res; // stop on first true result
    }
    return false;
}
CO4 Computing
fonte
0

Apenas uma atualização das respostas acima

function strsearch($findme, $source){
    if(is_array($findme)){
        if(str_replace($findme, '', $source) != $source){
            return true;
        }
    }else{
        if(strpos($source,$findme)){
            return true;
        }
    }
    return false;
}
Andy Nguyen
fonte