Pytanie Jak sprawdzić, czy ciąg zawiera określone słowo?


Rozważać:

$a = 'How are you?';

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

Załóżmy, że mam powyższy kod, jaki jest właściwy sposób napisania instrukcji if ($a contains 'are')?


2668


pochodzenie




Odpowiedzi:


Możesz użyć strpos() funkcja, która służy do znajdowania występowania jednego ciągu w innym:

$a = 'How are you?';

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

Zauważ, że użycie !== false jest celowe; strpos() zwraca offset, od którego zaczyna się ciąg igły w ciągu stogu siana lub wartość boolowska false jeśli igła nie zostanie znaleziona. Ponieważ 0 jest prawidłowym offsetem, a 0 to "falsey", nie możemy używać prostszych konstrukcji, takich jak !strpos($a, 'are').


5448



Jedną z rzeczy, które znalazłem, było to, że jeśli "jest" jest pierwszym słowem, powyższy kod się nie powiedzie, ponieważ zwraca "0", co można uznać za fałszywe! Aby tego uniknąć, powinien przeczytać: (strpos ("x". $ A, "are")! == false) ..... - Darknight
@Darknight: "0" nie jest uważane za "fałsz" podczas używania! ==. Jest brany pod uwagę tylko wtedy, gdy używasz! =. - Milan Babuškov
Bardzo późno na imprezę, ale bądź ostrożny z tym. To również zwróci true dla ciągu znaków "Czy ci na tym zależy?" - DTest
@DTest - oczywiście tak, zwróci true, ponieważ ciąg zawiera "jest". Jeśli szukasz konkretnie słowa ARE, musisz wykonać więcej sprawdzeń, na przykład sprawdzić, czy jest znak lub spacja przed A i po E. - jsherk
Bardzo dobre komentarze powyżej! Nigdy nie używam! = Lub ==, po wszystkim! == i === jest najlepszą opcją (moim zdaniem) uwzględniającą wszystkie aspekty (prędkość, dokładność itp.). - Melsi


Można użyć wyrażeń regularnych, lepiej dla dopasowywania słów w porównaniu do strpos, jak wspomniano przez innych użytkowników, zwróci to również true dla łańcuchów, takich jak taryfa, troska, stare itd. Tego można po prostu uniknąć w wyrażeniu regularnym, używając granic słów.

Prosty mecz może wyglądać mniej więcej tak:

$a = 'How are you?';

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

Po stronie wydajności, strpos jest około trzy razy szybszy i mając na uwadze, kiedy zrobiłem milion porównań na raz, zajęło to preg match 1,5 sekundy, aby zakończyć, a dla strpos zajęło 0,5 sekundy.


451



dzięki za sugestię, twój kod działa świetnie, ale wolę używać funkcji strpos. - Charles Yeung
@ Alexander.Plutov po drugie dajesz mi -1, a nie pytanie? cmon zajmuje 2 sekundy, aby odpowiedzieć w Google google.com/... - Breezer
+1 Jest to straszny sposób wyszukiwania prostego łańcucha znaków, ale wielu użytkowników SO szuka jakiegokolwiek sposobu na wyszukanie własnych podciągów, a sugestia jest pomocna. Nawet PO mógłby się nadmiernie uprościć - poinformować go o swoich alternatywach. - SamGoody
Technicznie pytanie pyta, jak znaleźć słowa nie podłańcuch. To faktycznie pomogło mi, ponieważ mogę użyć tego z ograniczeniami słów regularnych. Alternatywy są zawsze przydatne.
+1 dla odpowiedzi i -1 dla komentarza @ plutov.by, ponieważ strpos to tylko pojedyncze sprawdzenie, w międzyczasie wyrażenie regularne możesz sprawdzić wiele słów w tym samym czasie np: preg_match (/ are | you | not /) - albanx


Oto mała funkcja użyteczności przydatna w takich sytuacjach

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

198



@RobinvanBaalen Właściwie może poprawić czytelność kodu. Ponadto, downvotes mają być (dla) bardzo złych odpowiedzi, a nie dla "neutralnych". - Xaqq
Funkcje @RobinvanBaalen są prawie z definicji czytelne (aby przekazać ideę tego, co robisz). Porównaj, które jest bardziej czytelne: if ($email->contains("@") && $email->endsWith(".com)) { ... lub if (strpos($email, "@") !== false && substr($email, -strlen(".com")) == ".com") { ... - Brandin
@RobinvanBaalen w końcówce zasady mają zostać złamane. W przeciwnym razie ludzie nie wymyśliliby nowych, pomysłowych sposobów robienia rzeczy :). Dodatkowo muszę przyznać, że mam problem z zawijaniem umysłu wokół rzeczy takich jak na martinfowler.com. Zgadnij, co należy zrobić, to wypróbować różne rzeczy i dowiedzieć się, jakie podejścia są najwygodniejsze. - James P.
Inna opinia: posiadanie funkcji użyteczności, którą można łatwo owinąć, może pomóc w debugowaniu. Opiera się również na dobrych optymalizatorach, które eliminują taki narzut w usługach produkcyjnych. Wszystkie opinie mają ważne punkty. ;) - Tino
Oczywiście jest to przydatne. Powinieneś to zachęcić. Co się dzieje, jeśli w PHP 100 jest nowy i szybszy sposób na znalezienie lokalizacji ciągów znaków? Czy chcesz zmienić wszystkie miejsca, w których dzwonisz do strpos? Czy chcesz zmienić tylko zawiera w funkcji? - Cosmin


Podczas gdy większość z tych odpowiedzi powie ci, czy w łańcuchu pojawi się podłańcuch, zwykle nie jest to, czego szukasz, jeśli szukasz konkretnego słowo, a nie a podłańcuch.

Co za różnica? Substraty mogą pojawiać się w innych słowach:

  • "Są" na początku "obszaru"
  • "Są" na końcu "zająca"
  • "Są" w środku "taryf"

Jednym ze sposobów na złagodzenie tego byłoby użycie wyrażenia regularnego połączonego z granice słów (\b):

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

Ta metoda nie ma tych samych fałszywych alarmów, jak wyżej, ale ma kilka własnych błędów krawędzi. Granice słów pasują do znaków innych niż słowa (\W), które będą czymś, co nie jest a-z, A-Z, 0-9, lub _. Oznacza to, że cyfry i podkreślenia będą liczone jako znaki słowne, a takie scenariusze się nie powiedzie:

  • "Są" w "O czym myślisz?"
  • "Są" w "lol u dunno wut są 4?"

Jeśli chcesz czegoś dokładniejszego niż to, będziesz musiał zacząć parsować składnię języka angielskiego, a to jest całkiem duża puszka robaków (i mimo to zakłada właściwe użycie składni, która nie zawsze jest podana).


113



to powinna być odpowiedź kanoniczna. Bo szukamy słowai nie podłańcuchy, regex jest odpowiedni. Dodam też to \b dopasowuje dwie rzeczy \W nie, co czyni go doskonałym do znalezienia słowa w ciągu: dopasowuje początek ciągu znaków (^) i koniec napisu ($) - code_monk
To nie działa: 3v4l.org/vPk2V - Jimbo
to powinna być poprawna odpowiedź. reszta odpowiedzi znajdzie "są" w ciągu znaków, jak "nieważne" .. Jak wspomniano w @Dtest - Robert Sinclair
@RobertSinclair Czy to takie złe? Jeśli zapytałeś mnie, czy napis "do you care" zawiera słowo "jest", powiedziałbym "tak". Słowo "jest" jest wyraźnie podciągiem tego łańcucha. To jest osobne pytanie od "" "Czy" jest "jednym ze słów w łańcuchu" nieważne "" "". - Paulpro
@Paulpro Eventhough OP nie określił, że $ a jest frazą, jestem prawie pewien, że to było implikowane. Jego pytanie brzmiało, jak wykryć Słowo w Frazie. Nie, jeśli Słowo zawiera w sobie Słowo, które, jak zakładam, byłoby nieistotne często. - Robert Sinclair


Aby ustalić, czy łańcuch zawiera inny ciąg, możesz użyć funkcji 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";
}

?>

UWAGA:

Jeśli szukana igła znajduje się na początku stogu siana, zwróci pozycję 0, jeśli wykonasz a == Porównaj to, co nie zadziała, będziesz musiał zrobić ===

ZA == Znak jest porównaniem i sprawdza, czy zmienna / wyrażenie / stała po lewej ma tę samą wartość, co zmienna / wyrażenie / stała po prawej stronie.

ZA === Znak jest porównaniem, aby sprawdzić, czy dwie zmienne / wyrażenia / stałe są równe ANDmają ten sam typ - tj. oba są ciągami lub obydwa są liczbami całkowitymi.


93



podać źródło? maxi-pedia.com/string+contains+substring+PHP - btk


Za pomocą strstr() lub stristr() jeśli twoje wyszukiwanie powinno uwzględniać wielkość liter, to inna opcja.


57



Notatka na temat php.net/manual/en/function.strstr.php page: Uwaga: Jeśli chcesz tylko określić, czy dana igła występuje w stogu siana, użyj zamiast niej funkcji szybszego i mniej intensywnego użycia pamięci (strpos). - Jo Smo
@tastro Czy są na tym jakieś renomowane testy porównawcze? - Wayne Whitty
To może być wolniejsze, ale IMHO strstr($a, 'are') jest o wiele bardziej elegancka niż brzydka strpos($a, 'are') !== false. PHP naprawdę potrzebuje str_contains() funkcjonować. - Paul Spiegel


Patrzeć na 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





Jeśli chcesz uniknąć problemu "falsey" i "truthy", możesz użyć substr_count:

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

Jest nieco wolniejszy od strpos, ale unika problemów z porównaniem.


37





Zrobić użytek z dopasowanie niewrażliwe na przypadek za pomocą stripos():

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

37





Komentarze Peer to SamGoody i Lego Stormtroopr.

Jeśli szukasz algorytmu PHP do ranking wyników wyszukiwania na podstawie bliskości / trafności wielu słów tutaj jest szybki i łatwy sposób generowania wyników wyszukiwania tylko z PHP:

Problemy z innymi metodami wyszukiwania boolowskiego, takimi jak strpos(), preg_match(), strstr() lub stristr() 

  1. nie można wyszukać wielu słów
  2. wyniki są niezalogowane

Metoda PHP oparta na Wektor Space Model i tf-idf (terminowa częstotliwość-odwrotna częstotliwość dokumentu):

Brzmi trudno, ale jest zaskakująco łatwe.

Jeśli chcemy wyszukać wiele słów w ciągu, głównym problemem jest to, w jaki sposób przypisujemy wagę do każdego z nich?

Gdybyśmy mogli waga łańcucha w ciągu znaków na podstawie tego, jak reprezentatywni są z ciągu jako całości, możemy zamówić nasze wyniki przez te, które najlepiej pasują do zapytania.

To jest idea modelu przestrzeni wektorowej, niedaleko od sposobu wyszukiwania pełnotekstowego SQL:

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

PRZYPADEK 1

$query = 'are';

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

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

WYNIK

Array
(
    [1] => 0.52832083357372
)

PRZYPADEK 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>';

WYNIKI

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

PRZYPADEK 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>';

WYNIKI

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

Istnieje wiele ulepszeń, które należy wprowadzić ale model zapewnia sposób na uzyskanie dobrych wyników z naturalnych zapytań, które nie mają operatorów boolowskich, takich jak strpos(), preg_match(), strstr() lub stristr().

NOTA BENE

Opcjonalnie wyeliminowanie nadmiarowości przed wyszukiwaniem słów

  • w ten sposób zmniejszając rozmiar indeksu i powodując mniejsze zapotrzebowanie na miejsce do przechowywania

  • mniej dysku I / O

  • szybsze indeksowanie i konsekwentnie szybsze wyszukiwanie.

1. Normalizacja

  • Konwertuj cały tekst na małe litery

2. Eliminacja stoperów

  • Wyeliminuj słowa z tekstu, który nie ma żadnego prawdziwego znaczenia (jak "i", "lub", "", "dla" itp.)

3. Podstawianie słownika

  • Zastąp słowa innymi, które mają identyczne lub podobne znaczenie. (np. zastąp przykłady "głodnych" i "głodnych" słowami "głód")

  • Dalsze działania algorytmiczne (śnieżka) mogą być wykonywane w celu dalszego zredukowania słów do ich podstawowego znaczenia.

  • Zastąpienie nazw kolorów ich odpowiednikami w postaci heksadecymalnej

  • Redukcja wartości numerycznych poprzez zmniejszenie dokładności to inne sposoby normalizacji tekstu.

ZASOBY 


35