Question Comment puis-je vérifier si une chaîne contient un mot spécifique?


Considérer:

$a = 'How are you?';

if ($a contains 'are')
    echo 'true';

Supposons que j'ai le code ci-dessus, quelle est la bonne façon d'écrire la déclaration if ($a contains 'are')?


2668


origine


Réponses:


Vous pouvez utiliser le strpos() fonction qui est utilisée pour trouver l'occurrence d'une chaîne dans une autre:

$a = 'How are you?';

if (strpos($a, 'are') !== false) {
    echo 'true';
}

Notez que l'utilisation de !== false est délibéré; strpos() renvoie soit le décalage auquel la chaîne d'aiguille commence dans la chaîne haystack, soit le booléen false si l'aiguille n'est pas trouvée. Puisque 0 est un décalage valide et que 0 est "falsey", nous ne pouvons pas utiliser des constructions plus simples comme !strpos($a, 'are').


5436



Vous pouvez utiliser des expressions régulières, il est préférable d'utiliser des expressions telles que le tarif, le soin, le regard, etc. Cela peut être simplement évité dans l'expression régulière en utilisant des limites de mots.

Une simple correspondance pour sont pourraient ressembler à ceci:

$a = 'How are you?';

if (preg_match('/\bare\b/',$a))
    echo 'true';

En ce qui concerne les performances, les strpos sont environ trois fois plus rapides et ont en tête, quand j'ai fait un million de fois à la fois, il a fallu 1,5 secondes pour terminer et 0,5 seconde pour les strpos.


450



Voici une petite fonction utilitaire utile dans des situations comme celle-ci

// returns true if $needle is a substring of $haystack
function contains($needle, $haystack)
{
    return strpos($haystack, $needle) !== false;
}

195



Alors que la plupart de ces réponses vous diront si une sous-chaîne apparaît dans votre chaîne, ce n'est généralement pas ce que vous voulez si vous cherchez un particulier motet pas un sous-chaîne.

Quelle est la différence? Les sous-chaînes peuvent apparaître dans d'autres mots:

  • Les "are" au début de "area"
  • Les "sont" à la fin du "lièvre"
  • Les "sont" au milieu des "tarifs"

Une façon d'atténuer cela serait d'utiliser une expression régulière associée à les limites des mots (\b):

function containsWord($str, $word)
{
    return !!preg_match('#\\b' . preg_quote($word, '#') . '\\b#i', $str);
}

Cette méthode n'a pas les mêmes faux positifs notés ci-dessus, mais elle a ses propres cas limites. Les limites de mots correspondent à des caractères non-mots (\W), qui vont être tout ce qui n'est pas a-z, A-Z, 0-9, ou _. Cela signifie que les chiffres et les traits de soulignement seront comptés comme des caractères de mots et que des scénarios comme celui-ci échoueront:

  • Les "sont" dans "Qu'est-ce que vous pensez?"
  • Les "sont" dans "lol u ne sais pas wut ceux sont4?"

Si vous voulez quelque chose de plus précis que cela, vous devrez commencer à faire de l'analyse grammaticale en anglais, et c'est un gros bidon de vers (et suppose une bonne utilisation de la syntaxe, de toute façon, ce qui n'est pas toujours acquis).


113



Pour déterminer si une chaîne contient une autre chaîne, vous pouvez utiliser la fonction PHP strpos ().

int strpos ( string $haystack , mixed $needle [, int $offset = 0 ] )

<?php

$haystack = 'how are you';
$needle = 'are';

if (strpos($haystack,$needle) !== false) {
    echo "$haystack contains $needle";
}

?>

MISE EN GARDE:

Si l'aiguille que vous recherchez est au début de la botte de foin, elle renverra la position 0, si vous faites une == comparer cela ne fonctionnera pas, vous devrez faire un ===

UNE == signe est une comparaison et teste si la variable / expression / constante à gauche a la même valeur que la variable / expression / constante à droite.

UNE === signe est une comparaison pour voir si deux variables / expressions / constantes sont égales ANDont le même type - c'est-à-dire que les deux sont des chaînes ou les deux sont des entiers.


92



En utilisant strstr() ou stristr() Si votre recherche doit être insensible à la casse serait une autre option.


57



Regarder strpos():

<?php
    $mystring = 'abc';
    $findme   = 'a';
    $pos = strpos($mystring, $findme);

    // Note our use of ===. Simply, == would not work as expected
    // because the position of 'a' was the 0th (first) character.
    if ($pos === false) {
        echo "The string '$findme' was not found in the string '$mystring'.";
    }
    else {
        echo "The string '$findme' was found in the string '$mystring',";
        echo " and exists at position $pos.";
    }
?>

55



Si vous voulez éviter les problèmes "falsey" et "truthy", vous pouvez utiliser substr_count:

if (substr_count($a, 'are') > 0) {
    echo "at least one 'are' is present!";
}

C'est un peu plus lent que les strpos mais ça évite les problèmes de comparaison.


37



Se servir de insensibilité à la casse en utilisant stripos():

if (stripos($string,$stringToSearch) !== false) {
    echo 'true';
}

37



Peer à SamGoody et Lego Stormtroopr commentaires.

Si vous cherchez un algorithme PHP à classer les résultats de la recherche en fonction de la proximité / de la pertinence de plusieurs mots voici un moyen rapide et facile de générer des résultats de recherche avec PHP uniquement:

Problèmes avec les autres méthodes de recherche booléenne telles que strpos(), preg_match(), strstr() ou stristr() 

  1. ne peut pas rechercher plusieurs mots
  2. les résultats sont non classés

Méthode PHP basée sur Modèle d'espace vectoriel et tf-idf (fréquence fréquentielle-fréquence de document inverse):

Cela semble difficile mais étonnamment facile.

Si nous voulons rechercher plusieurs mots dans une chaîne, le problème principal est de savoir comment attribuer un poids à chacun d'eux.

Si nous pouvions pondérer les termes dans une chaîne basée sur la façon dont ils sont représentatifs de la chaîne dans son ensemble, nous pourrions ordonner nos résultats par ceux qui correspondent le mieux à la requête.

C'est l'idée du modèle d'espace vectoriel, pas loin de la façon dont la recherche en texte intégral SQL fonctionne:

function get_corpus_index($corpus = array(), $separator=' ') {

    $dictionary = array();

    $doc_count = array();

    foreach($corpus as $doc_id => $doc) {

        $terms = explode($separator, $doc);

        $doc_count[$doc_id] = count($terms);

        // tf–idf, short for term frequency–inverse document frequency, 
        // according to wikipedia is a numerical statistic that is intended to reflect 
        // how important a word is to a document in a corpus

        foreach($terms as $term) {

            if(!isset($dictionary[$term])) {

                $dictionary[$term] = array('document_frequency' => 0, 'postings' => array());
            }
            if(!isset($dictionary[$term]['postings'][$doc_id])) {

                $dictionary[$term]['document_frequency']++;

                $dictionary[$term]['postings'][$doc_id] = array('term_frequency' => 0);
            }

            $dictionary[$term]['postings'][$doc_id]['term_frequency']++;
        }

        //from http://phpir.com/simple-search-the-vector-space-model/

    }

    return array('doc_count' => $doc_count, 'dictionary' => $dictionary);
}

function get_similar_documents($query='', $corpus=array(), $separator=' '){

    $similar_documents=array();

    if($query!=''&&!empty($corpus)){

        $words=explode($separator,$query);

        $corpus=get_corpus_index($corpus, $separator);

        $doc_count=count($corpus['doc_count']);

        foreach($words as $word) {

            if(isset($corpus['dictionary'][$word])){

                $entry = $corpus['dictionary'][$word];


                foreach($entry['postings'] as $doc_id => $posting) {

                    //get term frequency–inverse document frequency
                    $score=$posting['term_frequency'] * log($doc_count + 1 / $entry['document_frequency'] + 1, 2);

                    if(isset($similar_documents[$doc_id])){

                        $similar_documents[$doc_id]+=$score;

                    }
                    else{

                        $similar_documents[$doc_id]=$score;

                    }
                }
            }
        }

        // length normalise
        foreach($similar_documents as $doc_id => $score) {

            $similar_documents[$doc_id] = $score/$corpus['doc_count'][$doc_id];

        }

        // sort from  high to low

        arsort($similar_documents);

    }   

    return $similar_documents;
}

CAS 1

$query = 'are';

$corpus = array(
    1 => 'How are you?',
);

$match_results=get_similar_documents($query,$corpus);
echo '<pre>';
    print_r($match_results);
echo '</pre>';

RÉSULTAT

Array
(
    [1] => 0.52832083357372
)

CAS 2

$query = 'are';

$corpus = array(
    1 => 'how are you today?',
    2 => 'how do you do',
    3 => 'here you are! how are you? Are we done yet?'
);

$match_results=get_similar_documents($query,$corpus);
echo '<pre>';
    print_r($match_results);
echo '</pre>';

RÉSULTATS

Array
(
    [1] => 0.54248125036058
    [3] => 0.21699250014423
)

CAS 3

$query = 'we are done';

$corpus = array(
    1 => 'how are you today?',
    2 => 'how do you do',
    3 => 'here you are! how are you? Are we done yet?'
);

$match_results=get_similar_documents($query,$corpus);
echo '<pre>';
    print_r($match_results);
echo '</pre>';

RÉSULTATS

Array
(
    [3] => 0.6813781191217
    [1] => 0.54248125036058
)

Il y a beaucoup d'améliorations à faire mais le modèle fournit un moyen d'obtenir de bons résultats à partir de requêtes naturelles, qui n'ont pas d'opérateurs booléens tels que strpos(), preg_match(), strstr() ou stristr().

NOTA BENE

Élimination éventuelle de la redondance avant de rechercher les mots

  • réduisant ainsi la taille de l'index et réduisant les besoins de stockage

  • moins d'E / S disque

  • indexation plus rapide et une recherche par conséquent plus rapide.

1. Normalisation

  • Convertir tout le texte en minuscules

2. Élimination des mots vides

  • Éliminer les mots du texte qui n'ont aucun sens réel (comme 'et', 'ou', 'le', 'pour', etc.)

3. Substitution de dictionnaire

  • Remplacer les mots par d'autres qui ont une signification identique ou similaire. (ex: remplacer les cas de «faim» et «faim» par «faim»)

  • D'autres mesures algorithmiques (boule de neige) peuvent être effectuées pour réduire davantage les mots à leur signification essentielle.

  • Le remplacement des noms de couleurs par leurs équivalents hexadécimaux

  • La réduction des valeurs numériques en réduisant la précision sont d'autres moyens de normaliser le texte.

RESSOURCES 


35