ฉันจะตรวจสอบว่าสตริงมีคำเฉพาะได้อย่างไร


2661

พิจารณา:

$a = 'How are you?';

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

สมมติว่าฉันมีรหัสข้างต้นเป็นวิธีที่ถูกต้องในการเขียนคำสั่งif ($a contains 'are')คืออะไร?

คำตอบ:


6892

คุณสามารถใช้strpos()ฟังก์ชั่นที่ใช้ในการค้นหาการเกิดขึ้นของหนึ่งสายภายในอีกหนึ่ง:

$a = 'How are you?';

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

หมายเหตุว่าการใช้!== falseเป็นเจตนา (ค่า!= falseมิได้=== trueจะกลับมาผลที่ต้องการ); strpos()ส่งกลับค่าออฟเซ็ตที่สตริงเข็มเริ่มต้นในสตริงแฮ็กสแต็กหรือบูลีนfalseหากไม่พบเข็ม เนื่องจาก 0 เป็น offset ที่ถูกต้องและ 0 คือ "falsey" เราจึงไม่สามารถใช้โครงสร้างที่ง่ายกว่า!strpos($a, 'are')นี้ได้


261
ดึกมากไปงานเลี้ยง แต่ระวังเรื่องนี้ด้วย สิ่งนี้จะส่งกลับค่าจริงสำหรับสตริง 'คุณสนใจหรือไม่'
DTest

167
@DTest - ใช่แน่นอนมันจะกลับมาจริงเพราะสตริงมี 'เป็น' หากคุณกำลังมองหาคำว่า ARE อยู่โดยเฉพาะคุณจะต้องทำการตรวจสอบเพิ่มเติมอย่างเช่นตรวจสอบว่ามีตัวละครหรือช่องว่างหน้า A และหลัง E.
jsherk

40
ความคิดเห็นที่ดีมากข้างต้น! ฉันไม่เคยใช้! = หรือ == หลังจากทั้งหมด! == และ === เป็นตัวเลือกที่ดีที่สุด
Melsi

10
@jsherk ทำไมไม่ลอง regexes ล่ะ? บางสิ่งเช่น "เป็น"
Giulio Muscarello

21
ฉันมักจะหลีกเลี่ยงปัญหานี้โดยใช้strpos($a, 'are') > -1เพื่อทดสอบจริงเสมอ จากมุมมองการแก้ไขข้อบกพร่องฉันพบว่าสมองของฉันสิ้นเปลืองวงจรนาฬิกาน้อยลงหากพิจารณาว่าบรรทัดถูกเขียนอย่างถูกต้องหรือไม่เมื่อฉันไม่ต้องนับสัญญาณที่ต่อเนื่องกัน
equazcion

608

คุณสามารถใช้นิพจน์ทั่วไปได้ดีกว่าสำหรับการจับคู่คำเมื่อเทียบกับstrposที่กล่าวถึงโดยผู้ใช้คนอื่นมันจะคืนค่าจริงสำหรับสตริงเช่นค่าโดยสารการดูแลจ้อง ฯลฯ ซึ่งสามารถหลีกเลี่ยงได้ในการแสดงออกปกติโดยใช้ขอบเขตของคำ

การจับคู่แบบง่ายอาจมีลักษณะเช่นนี้:

$a = 'How are you?';

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

ทางด้านการแสดงstrposนั้นเร็วกว่าและมีอยู่ในใจประมาณสามเท่าเมื่อฉันเปรียบเทียบหนึ่งล้านครั้งในเวลาเดียวมันใช้เวลาpreg_match1.5 วินาทีจึงจะเสร็จและstrposใช้เวลา 0.5 วินาที

แก้ไข: เพื่อค้นหาส่วนหนึ่งส่วนใดของสตริงไม่ใช่แค่คำต่อคำฉันขอแนะนำให้ใช้นิพจน์ทั่วไปเช่น

$a = 'How are you?';
$search = 'are y';
if(preg_match("/{$search}/i", $a)) {
    echo 'true';
}

iในตอนท้ายของการแสดงออกปกติที่มีการเปลี่ยนแปลงการแสดงออกปกติจะเป็นกรณีตายถ้าคุณไม่ต้องการที่คุณสามารถปล่อยให้มันออกมา

ตอนนี้อาจเป็นปัญหาได้ในบางกรณีเนื่องจากสตริงการค้นหา $ ไม่ได้รับการฆ่าเชื้อด้วยวิธีใด ๆ ฉันหมายความว่ามันอาจไม่ผ่านการตรวจสอบในบางกรณีราวกับว่า$searchเป็นอินพุตของผู้ใช้ที่พวกเขาสามารถเพิ่มสตริงที่อาจทำงานได้ บางคนแสดงออกปกติแตกต่างกัน ...

นอกจากนี้ยังเป็นเครื่องมือที่ยอดเยี่ยมสำหรับการทดสอบและดูคำอธิบายของนิพจน์ทั่วไปต่างๆRegex101

ในการรวมฟังก์ชั่นทั้งสองชุดไว้ในฟังก์ชั่นอเนกประสงค์เดียว (รวมถึงความไวของตัวพิมพ์เล็กและตัวพิมพ์ใหญ่) คุณสามารถใช้สิ่งต่อไปนี้:

function FindString($needle,$haystack,$i,$word)
{   // $i should be "" or "i" for case insensitive
    if (strtoupper($word)=="W")
    {   // if $word is "W" then word search instead of string in string search.
        if (preg_match("/\b{$needle}\b/{$i}", $haystack)) 
        {
            return true;
        }
    }
    else
    {
        if(preg_match("/{$needle}/{$i}", $haystack)) 
        {
            return true;
        }
    }
    return false;
    // Put quotes around true and false above to return them as strings instead of as bools/ints.
}

9
@ Alexander.Plutov ที่สองของทั้งหมดที่คุณให้ฉัน -1 และไม่ใช่คำถาม? cmon จะใช้เวลา 2 วินาทีในการ google คำตอบgoogle.com/…
Breezer

64
+1 มันเป็นวิธีที่น่ากลัวในการค้นหาสตริงอย่างง่าย ๆ แต่ผู้เข้าชมจำนวนมากใน SO กำลังมองหาวิธีใด ๆ ในการค้นหาสตริงย่อยของพวกเขาเอง แม้แต่ OP อาจมีการปรับให้กว้างเกินไป - ให้เขารู้ถึงทางเลือกของเขา
SamGoody

72
ในทางเทคนิคแล้วคำถามถามว่าจะหาคำศัพท์ไม่ใช่ซับสตริงได้อย่างไร สิ่งนี้ช่วยฉันได้จริงเพราะฉันสามารถใช้กับขอบเขตคำ regex ทางเลือกมีประโยชน์เสมอ

15
+1 สำหรับคำตอบและ -1 ถึง @ plutov.by แสดงความคิดเห็นเพราะ strpos เป็นเพียงการตรวจสอบเพียงครั้งเดียวในขณะเดียวกัน regexp คุณสามารถตรวจสอบหลายคำในเวลาเดียวกันเช่น: preg_match (/ เป็น | คุณ | ไม่ /)
albanx

4
นิพจน์ทั่วไปควรเป็นวิธีสุดท้าย การใช้งานในเรื่องเล็กน้อยควรไม่ได้รับการสนับสนุน ผมยืนยันเกี่ยวกับเรื่องนี้จากความสูงหลายปีของการขุดรหัสที่ไม่ดี
yentsun

257

นี่คือฟังก์ชั่นยูทิลิตี้เล็ก ๆ น้อย ๆ ที่มีประโยชน์ในสถานการณ์เช่นนี้

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

74
@RobinvanBaalen จริงๆแล้วมันสามารถปรับปรุงการอ่านรหัสได้ นอกจากนี้ downvotes ควรเป็นคำตอบที่ไม่ดี (มาก) ไม่ใช่สำหรับคำว่า "เป็นกลาง"
Xaqq

37
@RobinvanBaalen ฟังก์ชั่นเกือบตามคำนิยามสำหรับการอ่าน (เพื่อสื่อสารความคิดของสิ่งที่คุณทำ) เปรียบเทียบสิ่งที่อ่านได้มากขึ้น: if ($email->contains("@") && $email->endsWith(".com)) { ...หรือif (strpos($email, "@") !== false && substr($email, -strlen(".com")) == ".com") { ...
Brandin

3
@RobinvanBaalen ในกติกาสุดท้ายมีความหมายที่จะถูกทำลาย ไม่เช่นนั้นผู้คนจะไม่คิดวิธีสร้างสรรค์สิ่งใหม่ ๆ :) นอกจากนี้ยังต้องยอมรับว่าฉันมีปัญหาในการห่อใจสิ่งต่าง ๆ เช่นบน martinfowler.com คิดว่าสิ่งที่ถูกต้องคือลองทำสิ่งต่าง ๆ ด้วยตัวคุณเองและค้นหาว่าวิธีใดที่สะดวกที่สุด
James P.

5
ความคิดเห็นอื่น: การมีฟังก์ชั่นยูทิลิตี้ที่คุณสามารถห่อได้ง่ายสามารถช่วยในการดีบั๊ก นอกจากนี้ยังช่วยลดเสียงร้องสำหรับเครื่องมือเพิ่มประสิทธิภาพที่ดีซึ่งช่วยลดค่าใช้จ่ายดังกล่าวในบริการการผลิต ดังนั้นความคิดเห็นของทุกคนมีจุดที่ถูกต้อง ;)
Tino

18
ของหลักสูตรนี้มีประโยชน์ คุณควรสนับสนุนสิ่งนี้ จะเกิดอะไรขึ้นถ้าใน PHP 100 มีวิธีใหม่และเร็วกว่าในการค้นหาตำแหน่งสตริง คุณต้องการที่จะเปลี่ยนสถานที่ทั้งหมดของคุณที่คุณเรียก strpos? หรือคุณต้องการที่จะเปลี่ยนเฉพาะภายในที่มีฟังก์ชั่น?
Cosmin

143

ขณะที่ส่วนใหญ่ของคำตอบเหล่านี้จะบอกคุณถ้าปรากฏ substring ในสายของคุณที่มักจะไม่ได้สิ่งที่คุณต้องการหากคุณกำลังมองหาโดยเฉพาะอย่างยิ่งคำและไม่ย่อย

ความแตกต่างคืออะไร? สารตั้งต้นสามารถปรากฏในคำอื่น ๆ :

  • "เป็น" ที่จุดเริ่มต้นของ "พื้นที่"
  • "เป็น" ในตอนท้ายของ "กระต่าย"
  • "เป็น" ในช่วงกลางของ "ค่าโดยสาร"

วิธีหนึ่งในการลดสิ่งนี้คือการใช้การแสดงออกปกติควบคู่กับขอบเขตของคำ ( \b):

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

วิธีการนี้ไม่มีผลบวกปลอมที่ระบุไว้ข้างต้น แต่มีบางกรณีที่เป็นขอบของมันเอง ขอบเขตของคำตรงกับตัวละครที่ไม่ใช่คำ ( \W) ซึ่งกำลังจะเป็นอะไรที่ไม่a-z, A-Z, หรือ0-9 _นั่นหมายถึงตัวเลขและขีดล่างจะถูกนับเป็นตัวอักษรคำและสถานการณ์เช่นนี้จะล้มเหลว:

  • The "are" ใน "คุณคิดอะไรอยู่ _are_"
  • "มี" ใน "lol u dunno wut เหล่านั้น are4?"

หากคุณต้องการอะไรที่ถูกต้องมากกว่านี้คุณจะต้องเริ่มทำการแยกวิเคราะห์ไวยากรณ์ภาษาอังกฤษและนั่นก็เป็นเวิร์มขนาดใหญ่ที่น่าจับตามอง


24
นี่ควรเป็นคำตอบที่ยอมรับได้ เนื่องจากเรากำลังมองหาคำและไม่ใช่สารตั้งต้น regex จึงเหมาะสม ฉันจะเพิ่มที่\bตรงกับสองสิ่งที่\Wไม่เหมาะสำหรับการค้นหาคำในสตริง: มันตรงกับจุดเริ่มต้นของสตริง ( ^) และจุดสิ้นสุดของสตริง ( $)
code_monk

นี่ควรเป็นคำตอบที่ถูกต้อง .. คำตอบที่เหลือจะพบว่า "เป็น" ในสตริงเช่น "do you care" .. ดังที่ได้รับการกล่าวถึงโดย @Dtest
Robert Sinclair

@RobertSinclair แย่จังเหรอ? หากคุณถามฉันว่าสตริง "คุณสนใจ" มีคำว่า "คือ" ฉันจะพูดว่า "ใช่" คำว่า "เป็น" เป็นสตริงย่อยของสตริงนั้นอย่างชัดเจน นั่นเป็นคำถามที่แยกจาก "" "คือ" เป็น "หนึ่งในคำในสตริง" คุณสนใจ "" ""
พอล

@ Paulpro Eventhough OP ไม่ได้ระบุ $ a เป็นวลีฉันค่อนข้างแน่ใจว่ามันส่อให้เห็น ดังนั้นคำถามของเขาคือวิธีการตรวจจับคำในวลี ไม่ใช่ถ้า Word มี Word อยู่ข้างในซึ่งฉันจะถือว่าไม่เกี่ยวข้องบ่อยกว่านั้น
โรเบิร์ตซินแคล

@Jimbo มันใช้งานได้คุณเพิ่งพลาด `` 3v4l.org/ZRpYi
MetalWeirdo

125

เพื่อตรวจสอบว่ามีสตริงสตริงคุณสามารถใช้ฟังก์ชัน 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";
}

?>

ข้อควรระวัง:

หากเข็มที่คุณกำลังค้นหาอยู่ที่จุดเริ่มต้นของกองหญ้ามันจะกลับสู่ตำแหน่ง 0 หากคุณทำการ==เปรียบเทียบที่ไม่ได้ผลคุณจะต้องทำ===

==สัญญาณคือการเปรียบเทียบและการทดสอบว่าตัวแปร / การแสดงออก / คงที่ไปทางซ้ายมีค่าเช่นเดียวกับตัวแปร / การแสดงออก / คงไปทางขวา

===สัญญาณคือการเปรียบเทียบเพื่อดูว่าสองตัวแปร / expresions / คงที่จะเท่ากันANDมีชนิดเดียวกัน - คือทั้งสองสายหรือทั้งสองอย่างเป็นจำนวนเต็ม


67

ดูที่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.";
    }
?>

62

การใช้strstr()หรือstristr()หากการค้นหาของคุณควรจะกรณีตายจะเป็นอีกทางเลือกหนึ่ง


9
หมายเหตุในหน้าphp.net/manual/en/function.strstr.php : หมายเหตุ: หากคุณต้องการตรวจสอบว่ามีเข็มเฉพาะเกิดขึ้นในกองหญ้าหรือไม่ให้ใช้ฟังก์ชั่นหน่วยความจำอย่างเข้มข้นเร็วขึ้นและน้อยลงแทน)
Jo Smo

@tastro มีมาตรฐานที่มีชื่อเสียงในเรื่องนี้หรือไม่?
Wayne Whitty

นี่อาจช้ากว่านี้ แต่ IMHO strstr($a, 'are')นั้นสง่างามยิ่งกว่าขี้เหร่strpos($a, 'are') !== falseมาก PHP ต้องการstr_contains()ฟังก์ชั่น
Paul Spiegel

มันทำให้ฉันคิดว่านี่ไม่ใช่คำตอบที่ยอมรับ
kurdtpage


45

แสดงความคิดเห็นกับ SamGoody และ Lego Stormtroopr

หากคุณกำลังมองหาอัลกอริทึม PHP เพื่อจัดอันดับผลการค้นหาตามความใกล้เคียง / ความเกี่ยวข้องของคำหลายคำนี่เป็นวิธีที่รวดเร็วและง่ายดายในการสร้างผลลัพธ์การค้นหาด้วย PHP เท่านั้น:

ปัญหาเกี่ยวกับวิธีการค้นหาแบบตรรกะอื่น ๆ เช่นstrpos(), preg_match(), strstr()หรือstristr()

  1. ไม่สามารถค้นหาคำได้หลายคำ
  2. ผลลัพธ์ไม่ได้ถูกจัดอันดับ

วิธี PHP ตามVector Space Modelและtf-idf (คำศัพท์ความถี่ - ความถี่เอกสารผกผัน)

ฟังดูยาก แต่ก็ง่ายอย่างน่าประหลาดใจ

หากเราต้องการค้นหาคำหลาย ๆ คำในสตริงปัญหาหลักคือเรากำหนดน้ำหนักให้แต่ละคำได้อย่างไร

ถ้าเราสามารถลดน้ำหนักในแง่สตริงขึ้นอยู่กับวิธีที่พวกเขาเป็นตัวแทนของสตริงเป็นทั้งเราสามารถสั่งซื้อผลของเราโดยคนที่ดีที่สุดตรงกับแบบสอบถาม

นี่เป็นแนวคิดของโมเดลพื้นที่เวกเตอร์ซึ่งอยู่ไม่ไกลจากวิธีการค้นหาข้อความแบบเต็มของ 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;
}

กรณีที่ 1

$query = 'are';

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

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

ผลลัพธ์

Array
(
    [1] => 0.52832083357372
)

กรณีที่ 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>';

ผล

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

กรณีที่ 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>';

ผล

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

มีมากมายของการปรับปรุงที่จะทำมี แต่รูปแบบมีวิธีการได้รับผลดีจากการสืบค้นธรรมชาติซึ่งไม่ได้มีการดำเนินการทางตรรกะเช่นstrpos(), preg_match(), หรือstrstr()stristr()

NOTA BENE

เลือกกำจัดความซ้ำซ้อนก่อนค้นหาคำ

  • จึงลดขนาดดัชนีและทำให้ต้องการพื้นที่จัดเก็บน้อยลง

  • I / O ของดิสก์น้อยลง

  • การจัดทำดัชนีที่เร็วขึ้นและการค้นหาที่เร็วขึ้น

1. การทำให้เป็นมาตรฐาน

  • แปลงข้อความทั้งหมดเพื่อกรณีที่ต่ำกว่า

2. การกำจัดคำหยุด

  • กำจัดคำจากข้อความที่ไม่มีความหมายที่แท้จริง (เช่น 'และ', 'หรือ', 'the', 'for' ฯลฯ )

3. การทดแทนพจนานุกรม

  • แทนที่คำด้วยคำอื่น ๆ ที่มีความหมายเหมือนหรือคล้ายกัน (เช่นแทนที่อินสแตนซ์ 'hungrily' และ 'หิว' ด้วย 'หิว')

  • อาจใช้มาตรการอัลกอริธึมเพิ่มเติม (สโนว์บอล) เพื่อลดคำต่อความหมายที่จำเป็น

  • การแทนที่ชื่อสีด้วยค่าฐานสิบหกที่เทียบเท่ากัน

  • การลดค่าตัวเลขโดยการลดความแม่นยำเป็นวิธีการอื่นในการทำให้ข้อความเป็นมาตรฐาน

ทรัพยากร


40

หากคุณต้องการหลีกเลี่ยงปัญหา "เท็จ" และ "ความจริง" คุณสามารถใช้ substr_count:

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

มันช้ากว่า strpos เล็กน้อย แต่ก็หลีกเลี่ยงปัญหาการเปรียบเทียบ


มันกลับมาfalseสำหรับ "คุณแน่ใจเหรอ?" เนื่องจากตำแหน่งสำหรับstrposคือ0
Hafenkranich

30

อีกทางเลือกหนึ่งคือใช้ฟังก์ชั่นstrstr () สิ่งที่ต้องการ:

if (strlen(strstr($haystack,$needle))>0) {
// Needle Found
}

จุดที่ควรทราบ: ฟังก์ชั่น strstr () เป็นกรณี ๆ ไป สำหรับการค้นหากรณีตายใช้stristr ()ฟังก์ชั่น


1
strstr () ส่งคืน FALSE หากไม่พบเข็ม ดังนั้นจึงไม่จำเป็นต้องใช้ strlen
Ayesh K

29
if (preg_match('/(are)/', $a)) {
   echo 'true';
}

3
ฉันได้รับคำเตือนต่อไปนี้:WARNING preg_match(): Delimiter must not be alphanumeric or backslash
Pathros

27

ฉันบิตประทับใจไม่มีคำตอบที่นี่เป็นที่ที่ใช้strpos, strstrและฟังก์ชั่นที่คล้ายกันกล่าวถึงฟังก์ชั่นหลายไบต์สตริงเลย (2015/05/08)

โดยทั่วไปหากคุณมีปัญหาในการค้นหาคำที่มีอักขระเฉพาะสำหรับบางภาษาเช่นเยอรมันฝรั่งเศสโปรตุเกสสเปน ฯลฯ (เช่น: ä , é , ô , ç , º , ñ ) คุณอาจต้องการนำหน้า mb_ฟังก์ชั่นที่มี ดังนั้นคำตอบที่ยอมรับจะใช้mb_strposหรือmb_stripos(สำหรับการจับคู่แบบตรงตามตัวพิมพ์เล็กและใหญ่) แทน:

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

หากคุณไม่สามารถรับประกันได้ว่าข้อมูลทั้งหมดของคุณเป็น 100% ใน UTF-8คุณอาจต้องการใช้mb_ฟังก์ชั่น

บทความที่ดีที่จะเข้าใจว่าทำไมเป็นนักพัฒนาแอปโซลูทุกขั้นต่ำของซอฟท์แวแน่นอนบวกต้องทราบเกี่ยวกับ Unicode และชุดตัวอักษร (ไม่มีข้อแก้ตัว!)โดยโจ Spolsky


25

ใน PHP วิธีที่ดีที่สุดในการตรวจสอบว่าสตริงมีซับสตริงที่แน่นอนหรือไม่คือการใช้ฟังก์ชันตัวช่วยอย่างง่ายเช่นนี้

function contains($haystack, $needle, $caseSensitive = false) {
    return $caseSensitive ?
            (strpos($haystack, $needle) === FALSE ? FALSE : TRUE):
            (stripos($haystack, $needle) === FALSE ? FALSE : TRUE);
}

คำอธิบาย:

  • strpos ค้นหาตำแหน่งของการเกิดขึ้นครั้งแรกของสตริงย่อยที่เล็กตามตัวอักษรในสตริง
  • stripos ค้นหาตำแหน่งของการเกิดขึ้นครั้งแรกของสตริงย่อยที่ไม่คำนึงถึงขนาดตัวพิมพ์ในสตริง
  • myFunction($haystack, $needle) === FALSE ? FALSE : TRUEตรวจสอบให้แน่ใจว่าmyFunctionส่งคืนบูลีนเสมอและแก้ไขพฤติกรรมที่ไม่คาดคิดเมื่อดัชนีของสตริงย่อยเป็น 0
  • $caseSensitive ? A : Bเลือกอย่างใดอย่างหนึ่งstrposหรือจะทำผลงานขึ้นอยู่กับมูลค่าของstripos$caseSensitive

เอาท์พุท:

var_dump(contains('bare','are'));            // Outputs: bool(true)
var_dump(contains('stare', 'are'));          // Outputs: bool(true)
var_dump(contains('stare', 'Are'));          // Outputs: bool(true)
var_dump(contains('stare', 'Are', true));    // Outputs: bool(false)
var_dump(contains('hair', 'are'));           // Outputs: bool(false)
var_dump(contains('aren\'t', 'are'));        // Outputs: bool(true)
var_dump(contains('Aren\'t', 'are'));        // Outputs: bool(true)
var_dump(contains('Aren\'t', 'are', true));  // Outputs: bool(false)
var_dump(contains('aren\'t', 'Are'));        // Outputs: bool(true)
var_dump(contains('aren\'t', 'Are', true));  // Outputs: bool(false)
var_dump(contains('broad', 'are'));          // Outputs: bool(false)
var_dump(contains('border', 'are'));         // Outputs: bool(false)

22

ฟังก์ชั่นด้านล่างใช้งานได้และไม่ขึ้นอยู่กับฟังก์ชั่นอื่น ๆ มันใช้การจัดการสตริง PHP ดั้งเดิมเท่านั้น ส่วนตัวผมไม่แนะนำสิ่งนี้ แต่คุณสามารถดูวิธีการทำงาน:

<?php

if (!function_exists('is_str_contain')) {
  function is_str_contain($string, $keyword)
  {
    if (empty($string) || empty($keyword)) return false;
    $keyword_first_char = $keyword[0];
    $keyword_length = strlen($keyword);
    $string_length = strlen($string);

    // case 1
    if ($string_length < $keyword_length) return false;

    // case 2
    if ($string_length == $keyword_length) {
      if ($string == $keyword) return true;
      else return false;
    }

    // case 3
    if ($keyword_length == 1) {
      for ($i = 0; $i < $string_length; $i++) {

        // Check if keyword's first char == string's first char
        if ($keyword_first_char == $string[$i]) {
          return true;
        }
      }
    }

    // case 4
    if ($keyword_length > 1) {
      for ($i = 0; $i < $string_length; $i++) {
        /*
        the remaining part of the string is equal or greater than the keyword
        */
        if (($string_length + 1 - $i) >= $keyword_length) {

          // Check if keyword's first char == string's first char
          if ($keyword_first_char == $string[$i]) {
            $match = 1;
            for ($j = 1; $j < $keyword_length; $j++) {
              if (($i + $j < $string_length) && $keyword[$j] == $string[$i + $j]) {
                $match++;
              }
              else {
                return false;
              }
            }

            if ($match == $keyword_length) {
              return true;
            }

            // end if first match found
          }

          // end if remaining part
        }
        else {
          return false;
        }

        // end for loop
      }

      // end case4
    }

    return false;
  }
}

ทดสอบ:

var_dump(is_str_contain("test", "t")); //true
var_dump(is_str_contain("test", "")); //false
var_dump(is_str_contain("test", "test")); //true
var_dump(is_str_contain("test", "testa")); //flase
var_dump(is_str_contain("a----z", "a")); //true
var_dump(is_str_contain("a----z", "z")); //true 
var_dump(is_str_contain("mystringss", "strings")); //true 

13
คุณพอจะบอกฉันหน่อยได้ไหมว่าทำไมในโลกนี้ที่คุณจะใช้ฟังก์ชั่นแบบนี้เมื่อ strpos เป็นทางออกที่ดีที่สุด?
sg3s

3
@ sg3s: คุณมีสิทธิ์อย่างสมบูรณ์ แต่ strpos ยังขึ้นอยู่กับสิ่งนั้นเช่นกันฉันไม่ได้โพสต์ไว้สำหรับตัวแทนเพียงเพื่อแบ่งปันความรู้เล็กน้อย
Jason OOO

var_dump สุดท้ายเป็นเท็จ
Sunny

1
@Sunny: มันเป็น typo: var_dump (is_str_contain ("mystringss", "สตริง")); // true
Jason OOO

22

คุณสามารถใช้strstrฟังก์ชั่น:

$haystack = "I know programming";
$needle   = "know";
$flag = strstr($haystack, $needle);

if ($flag){

    echo "true";
}

โดยไม่ต้องใช้ฟังก์ชั่น inbuilt:

$haystack  = "hello world";
$needle = "llo";

$i = $j = 0;

while (isset($needle[$i])) {
    while (isset($haystack[$j]) && ($needle[$i] != $haystack[$j])) {
        $j++;
        $i = 0;
    }
    if (!isset($haystack[$j])) {
        break;
    }
    $i++;
    $j++;

}
if (!isset($needle[$i])) {
    echo "YES";
}
else{
    echo "NO ";
}

2
เกิดปัญหาถ้าคุณค้นหาคำแรก
T30

20

ฉันมีปัญหากับเรื่องนี้และสุดท้ายฉันก็เลือกที่จะสร้างทางออกของตัวเอง โดยไม่ใช้เอ็นจิ้นนิพจน์ทั่วไป :

function contains($text, $word)
{
    $found = false;
    $spaceArray = explode(' ', $text);

    $nonBreakingSpaceArray = explode(chr(160), $text);

    if (in_array($word, $spaceArray) ||
        in_array($word, $nonBreakingSpaceArray)
       ) {

        $found = true;
    }
    return $found;
 }

คุณอาจสังเกตเห็นว่าคำตอบก่อนหน้านี้ไม่ใช่คำตอบสำหรับคำที่ใช้เป็นคำนำหน้าสำหรับคำอื่น ในการใช้ตัวอย่างของคุณ:

$a = 'How are you?';
$b = "a skirt that flares from the waist";
$c = "are";

กับตัวอย่างข้างต้นทั้งสอง$aและ$bมี$cแต่คุณอาจต้องการการทำงานของคุณจะบอกคุณว่ามีเพียงมี$a$c


1
คุณอาจหมายถึง: $found = falseที่จุดเริ่มต้น
slownage

1
ฟังก์ชั่นของคุณอาจไม่ทำงานหากคำนั้นเชื่อมโยงกับเครื่องหมายจุลภาคเครื่องหมายคำถามหรือจุด เช่น "สิ่งที่คุณเห็นคือสิ่งที่คุณได้รับ" และคุณต้องการพิจารณาว่า "รับ" อยู่ในประโยคหรือไม่ สังเกตเห็นการหยุดเต็มรูปแบบถัดจาก "รับ" ในกรณีนี้ฟังก์ชั่นของคุณจะคืนค่าเป็นเท็จ ขอแนะนำให้ใช้การแสดงออกปกติหรือ substr (ฉันคิดว่ามันใช้การแสดงออกปกติอยู่แล้ว) เพื่อค้นหา / แทนที่สตริง
lightbringer

@ lightbringer คุณอาจไม่ผิดกับคำแนะนำของคุณมากขึ้นมันหมายความว่าอะไรสำหรับคุณ "ขอแนะนำ"? ไม่มีบุคคลที่ยิ่งใหญ่ที่แนะนำหรือแก้ไข มันเกี่ยวกับการใช้งานเอ็นจิ้นนิพจน์ทั่วไปใน php ซึ่งเป็น blackhole ในภาษาของตัวเองคุณอาจต้องการลองวาง regex ที่ตรงกันลงในลูปและทำการเปรียบเทียบผลลัพธ์
หลอกลวง

คำตอบนี้แสดงให้เห็นอย่างไม่ดีและล้มเหลวกับสถานการณ์จำลองจำนวนมาก ฉันไม่เห็นประโยชน์ใด ๆ ในความบันเทิงเทคนิคนี้ นี่คือฟังก์ชั่นที่กำหนดเองที่ได้รับการปรับปรุงและการโทรซ้ำ: 3v4l.org/E9dfDฉันไม่มีความสนใจในการแก้ไขวิกินี้เพราะฉันคิดว่ามันเสียเวลานักวิจัย
mickmackusa

18

ตัวเลือกอื่นในการค้นหาการเกิดขึ้นของคำจากสตริงโดยใช้strstr ()และstristr ()เป็นดังนี้:

<?php
    $a = 'How are you?';
    if (strstr($a,'are'))  // Case sensitive
        echo 'true';
    if (stristr($a,'are'))  // Case insensitive
        echo 'true';
?>

นี่คือถอยหลัง iในstristrย่อมาจากความรู้สึก
Adam Merrifield

18

มีคำตอบมากมายที่ใช้substr_countตรวจสอบว่าผลลัพธ์คือ>0อะไร แต่เนื่องจากifคำสั่งพิจารณาว่าศูนย์เหมือนกับเท็จคุณสามารถหลีกเลี่ยงการตรวจสอบและเขียนโดยตรง:

if (substr_count($a, 'are')) {

ในการตรวจสอบว่าไม่มีอยู่ให้เพิ่ม!โอเปอเรเตอร์:

if (!substr_count($a, 'are')) {

ดี ... จริงบางส่วนใน php 0 == false เป็นความจริง แต่ 0 === false เป็นเท็จ
Andrejs Gubars

17

สามารถทำได้สามวิธี:

 $a = 'How are you?';

1- stristr ()

 if (strlen(stristr($a,"are"))>0) {
    echo "true"; // are Found
 } 

2- strpos ()

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

3- preg_match ()

 if( preg_match("are",$a) === 1) {
   echo "true"; // are Found
 }

ดี แต่ preg_match มีความเสี่ยงเนื่องจากสามารถส่งคืนค่าเท็จหรือ 0 คุณควรทำการทดสอบ === 1 ใน # 3
Shapeshifter

14

รุ่นสั้น

$result = false!==strpos($a, 'are');

5
ในขณะที่ข้อมูลโค้ดนี้อาจแก้ไขคำถามรวมถึงคำอธิบายช่วยปรับปรุงคุณภาพของโพสต์ของคุณ จำไว้ว่าคุณกำลังตอบคำถามสำหรับผู้อ่านในอนาคตและคนเหล่านั้นอาจไม่ทราบสาเหตุของการแนะนำรหัสของคุณ
Bono

14

เพื่อค้นหา 'คำ' แทนที่จะเกิดตัวอักษรขึ้นมาหลาย ๆ ชุดซึ่งในความเป็นจริงอาจเป็นส่วนหนึ่งของคำอื่น ๆ ต่อไปนี้จะเป็นทางออกที่ดี

$string = 'How are you?';
$array = explode(" ", $string);

if (in_array('are', $array) ) {
    echo 'Found the word';
}

5
มันจะล้มเหลวถ้า$stringเป็นAre are, are?
Sunny

13

คุณควรใช้รูปแบบตัวพิมพ์เล็กและตัวพิมพ์เล็กดังนั้นหากค่าที่ป้อนอยู่ในsmallหรือcapsไม่สำคัญ

<?php
$grass = "This is pratik joshi";
$needle = "pratik";
if (stripos($grass,$needle) !== false) { 

 /*If i EXCLUDE : !== false then if string is found at 0th location, 
   still it will say STRING NOT FOUND as it will return '0' and it      
   will goto else and will say NOT Found though it is found at 0th location.*/
    echo 'Contains word';
}else{
    echo "does NOT contain word";
}
?>

ที่นี่แถบค้นหาเข็มใน heystack โดยไม่คำนึงถึงกรณี (เล็ก / หมวก)

ตัวอย่าง PHPCode พร้อมเอาต์พุต


13

บางทีคุณอาจใช้สิ่งนี้:

<?php
    findWord('Test all OK');

    function findWord($text) {
        if (strstr($text, 'ok')) {
            echo 'Found a word';
        }
        else
        {
            echo 'Did not find a word';
        }
    }
?>

12

ห้ามใช้preg_match()หากคุณต้องการตรวจสอบว่ามีสตริงหนึ่งอยู่ในสตริงอื่นหรือไม่ ใช้strpos()หรือstrstr()แทนเนื่องจากจะเร็วขึ้น ( http://in2.php.net/preg_match )

if (strpos($text, 'string_name') !== false){
   echo 'get the string';
}

12

หากคุณต้องการตรวจสอบว่าสตริงมีคำเฉพาะหลายคำหรือไม่คุณสามารถทำได้:

$badWords = array("dette", "capitale", "rembourser", "ivoire", "mandat");

$string = "a string with the word ivoire";

$matchFound = preg_match_all("/\b(" . implode($badWords,"|") . ")\b/i", $string, $matches);

if ($matchFound) {
    echo "a bad word has been found";
}
else {
    echo "your string is okay";
}

สิ่งนี้มีประโยชน์ในการหลีกเลี่ยงสแปมเมื่อส่งอีเมลเช่น


10

ฟังก์ชั่นการทำงานที่ดี strpos แต่ถ้าคุณต้องการที่จะทำcase-insensitiveการตรวจสอบคำในวรรคแล้วคุณสามารถใช้ประโยชน์จากการทำงานของstriposPHP

ตัวอย่างเช่น,

$result = stripos("I love PHP, I love PHP too!", "php");
if ($result === false) {
    // Word does not exist
}
else {
    // Word exists
}

ค้นหาตำแหน่งที่เกิดขึ้นครั้งแรกของสตริงย่อยที่ไม่ต้องคำนึงถึงตัวพิมพ์ใหญ่ - เล็กในสตริง

ถ้าคำนั้นไม่มีอยู่ในสตริงมันจะส่งคืนค่าเท็จอื่นมันจะส่งคืนตำแหน่งของคำนั้น


9

คุณต้องใช้ตัวดำเนินการเหมือนกัน / ไม่เหมือนกันเพราะ strpos สามารถส่งคืนค่า 0 เนื่องจากเป็นค่าดัชนี หากคุณชอบผู้ประกอบการที่ประกอบไปด้วยไตร่ตรองลองใช้สิ่งต่อไปนี้ (ดูย้อนหลังนิดหน่อยฉันจะยอมรับ):

echo FALSE === strpos($a,'are') ? 'false': 'true';

8

ตรวจสอบว่าสายอักขระมีคำเฉพาะหรือไม่

ซึ่งหมายความว่าจะต้องแก้ไขสตริงเป็นคำ (ดูหมายเหตุด้านล่าง)

วิธีหนึ่งในการทำเช่นนี้และเพื่อระบุตัวคั่นคือการใช้preg_split( doc ):

<?php

function contains_word($str, $word) {
  // split string into words
  // separators are substrings of at least one non-word character
  $arr = preg_split('/\W+/', $str, NULL, PREG_SPLIT_NO_EMPTY);

  // now the words can be examined each
  foreach ($arr as $value) {
    if ($value === $word) {
      return true;
    }
  }
  return false;
}

function test($str, $word) {
  if (contains_word($str, $word)) {
    echo "string '" . $str . "' contains word '" . $word . "'\n";
  } else {
    echo "string '" . $str . "' does not contain word '" . $word . "'\n" ;
  }
}

$a = 'How are you?';

test($a, 'are');
test($a, 'ar');
test($a, 'hare');

?>

การวิ่งให้

$ php -f test.php                   
string 'How are you?' contains word 'are' 
string 'How are you?' does not contain word 'ar'
string 'How are you?' does not contain word 'hare'

หมายเหตุ: ที่นี่เราไม่ได้หมายถึงคำสำหรับทุกลำดับของสัญลักษณ์

คำจำกัดความที่ใช้งานจริงของคำนั้นอยู่ในความหมายของเอ็นจิ้นการแสดงออกปกติของ PCRE โดยที่คำนั้นเป็นสตริงย่อยที่ประกอบด้วยอักขระคำเท่านั้นโดยจะถูกคั่นด้วยอักขระที่ไม่ใช่คำ

อักขระ "คำ" คือตัวอักษรหรือตัวเลขหรือตัวอักษรขีดล่างซึ่งก็คือตัวอักษรใด ๆ ที่สามารถเป็นส่วนหนึ่งของคำว่า "Perl" คำจำกัดความของตัวอักษรและตัวเลขถูกควบคุมโดยตารางอักขระของ PCRE และอาจแตกต่างกันไปหากการจับคู่แบบระบุตำแหน่งกระทำการ (.. )


7

โซลูชันอื่นสำหรับสตริงเฉพาะ:

$subject = 'How are you?';
$pattern = '/are/';
preg_match($pattern, $subject, $match);
if ($match[0] == 'are') {
    echo true;
}

คุณยังสามารถใช้strpos()ฟังก์ชั่น

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.