การทดสอบที่มีประสิทธิภาพที่สุดว่าสตริง PHP ลงท้ายด้วยสตริงอื่นหรือไม่?


125

วิธี PHP มาตรฐานในการทดสอบว่าสตริง$strลงท้ายด้วยสตริงย่อย$testคือ:

$endsWith = substr( $str, -strlen( $test ) ) == $test

วิธีนี้เป็นวิธีที่เร็วที่สุดหรือไม่?


2
คล้ายกัน: stackoverflow.com/questions/834303/…
trante

คุณอาจพบs($str)->endsWith($test)หรือs($str)->endsWithIgnoreCase($test)เป็นประโยชน์ดังที่พบในไลบรารีแบบสแตนด์อโลนนี้
caw

คำตอบ:


152

สิ่งที่อัสซาฟพูดนั้นถูกต้อง มีฟังก์ชันในตัวใน PHP เพื่อทำเช่นนั้น

substr_compare($str, $test, strlen($str)-strlen($test), strlen($test)) === 0;

ถ้า$testยาวเกิน$strPHP จะเตือนดังนั้นคุณต้องตรวจสอบก่อน

function endswith($string, $test) {
    $strlen = strlen($string);
    $testlen = strlen($test);
    if ($testlen > $strlen) return false;
    return substr_compare($string, $test, $strlen - $testlen, $testlen) === 0;
}

ดี ดูเหมือนว่าการเปรียบเทียบในสถานที่จะเร็วกว่า substr () ตามที่ Assaf ชี้ให้เห็น
Jason Cohen

2
คำตอบของ mcrumley นั้นยอดเยี่ยม แต่ควรใช้ '===' แทน '==' '===' เข้มงวดกว่าและมักจะทำในสิ่งที่คุณต้องการในขณะที่ '==' อาจนำไปสู่ความประหลาดใจที่น่ารังเกียจ ข้อมูลโค้ดที่สามของ mcrumley ถูกต้อง แต่สองข้อแรกไม่ถูกต้อง substr_compare () ส่งคืนเท็จในบางกรณีข้อผิดพลาด ใน PHP เท็จ == 0 ดังนั้นข้อมูลโค้ดจะส่งสัญญาณว่าพบสตริงแล้ว ด้วย === สิ่งนี้จะไม่เกิดขึ้น
jcsahnwaldt Reinstate Monica

1
วันนี้ฉันพบข้อผิดพลาดซึ่งจะทำลายโซลูชันที่คุณให้ตั้งแต่ PHP 5.5.11 ขึ้นไป bugs.php.net/bug.php?id=67043
user2180613

3 ฟังก์ชั่นการโทรเหนือศีรษะไม่ได้ทำให้เร็วที่สุด
Thanh Trung

66

วิธีนี้มีราคาแพงกว่าหน่วยความจำเล็กน้อย แต่เร็วกว่า:

stripos(strrev($haystack), $reversed_needle) === 0;

วิธีนี้ดีที่สุดเมื่อคุณรู้แน่ชัดว่าเข็มคืออะไรดังนั้นคุณสามารถฮาร์ดโค้ดกลับด้านได้ หากคุณย้อนกลับตามโปรแกรมเข็มจะช้ากว่าวิธีก่อนหน้านี้


2
-1 ฉันสงสัยอย่างจริงจังว่านี่เร็วกว่านี้และมันก็ยุ่งยาก (เจ๋ง แต่มักไม่ค่อยมีประโยชน์) หากกองหญ้าไม่ได้ลงท้ายด้วยเข็มstriposจะวนซ้ำทั้งเส้นในกรณีที่เลวร้ายที่สุดในขณะที่substr_compareจะเปรียบเทียบความยาวของเข็มมากที่สุด ใช่substr_compareต้องคำนวณความยาวของกองหญ้า (และเข็มที่เล็กกว่ามาก) แต่วิธีนี้ต้องการและคัดลอกแบบเต็มและอาจแปลงสิ่งทั้งหมดเป็นตัวพิมพ์เล็กเพื่อบูต
David Harkness

แนวทางเจ๋ง ๆ แต่ไม่มีประสิทธิภาพ (ตามที่กล่าวไว้ในคำตอบเอง) ในหลาย ๆ กรณี! ยังคงมีการโหวตเพิ่มขึ้นสำหรับการมีความคิดสร้างสรรค์ที่แปลกประหลาดและแสดงให้เห็นว่ามีวิธีอื่น ๆ ในการทำสิ่งเดียวกันที่คุณอาจจินตนาการได้เสมอ ไชโย!
Fr0zenFyr

1
ฉันทดสอบและพบวิธีนี้เร็วกว่าคำตอบที่ยอมรับ แม้ว่าทั้งกองฟางและเข็มจะพลิกกลับในขณะบิน แต่ก็เร็วกว่า
Shumoapp

@DavidHarkness คุณได้ทดสอบเพื่อดูว่าข้อสงสัยของคุณได้รับการรับรองหรือไม่?
นาธา

@ นาธานไม่มันไม่คุ้มค่ากับเวลาในการเปรียบเทียบเนื่องจากsubstr_compare()ทำงานได้ดี
David Harkness

61
$endsWith = substr_compare( $str, $test, -strlen( $test ) ) === 0

ออฟเซ็ตเชิงลบ "เริ่มนับจากจุดสิ้นสุดของสตริง"


3
IMO เป็นหนึ่งในวิธีที่ดีที่สุดจากโซลูชันที่มีให้
Roman Podlinov

+200 ถ้าฉันทำได้ ข้อมูลเชิงลึกที่สำคัญในที่นี้คือการใช้ความยาวเชิงลบจะทำให้ส่วนท้ายของสตริง คุณยังสามารถใช้ substr ที่มีความยาว -ve และทำการ == เทียบกับ $ test คำตอบอื่น ๆ น่าสงสาร
Nick

11

ต่อไปนี้เป็นวิธีง่ายๆในการตรวจสอบว่าสตริงหนึ่งลงท้ายด้วยอีกสตริงหรือไม่โดยให้strposค่าชดเชยตรงที่ควรจะพบสตริง:

function stringEndsWith($whole, $end)
{
    return (strpos($whole, $end, strlen($whole) - strlen($end)) !== false);
}

ตรงไปตรงมาและฉันคิดว่ามันจะใช้ได้ใน PHP 4


8

ขึ้นอยู่กับประเภทของประสิทธิภาพที่คุณสนใจ

เวอร์ชันของคุณใช้หน่วยความจำมากขึ้นเนื่องจากสำเนาเพิ่มเติมจากการใช้ substr

เวอร์ชันทางเลือกอาจค้นหาสตริงต้นฉบับสำหรับการเกิดสตริงย่อยสุดท้ายโดยไม่ต้องทำสำเนา แต่อาจช้ากว่าเนื่องจากมีการทดสอบมากขึ้น

วิธีที่มีประสิทธิภาพมากที่สุดคือการทำ loop char-by-char จากตำแหน่ง -sterlen (test) จนถึงจุดสิ้นสุดของสตริงและเปรียบเทียบ นั่นเป็นการเปรียบเทียบเพียงเล็กน้อยที่คุณคาดหวังได้และแทบจะไม่ต้องใช้หน่วยความจำเพิ่มเติมเลย



3

ฉันหวังว่าคำตอบด้านล่างอาจมีประสิทธิภาพและเรียบง่าย:

$content = "The main string to search";
$search = "search";
//For compare the begining string with case insensitive. 
if(stripos($content, $search) === 0) echo 'Yes';
else echo 'No';

//For compare the begining string with case sensitive. 
if(strpos($content, $search) === 0) echo 'Yes';
else echo 'No';

//For compare the ending string with case insensitive. 
if(stripos(strrev($content), strrev($search)) === 0) echo 'Yes';
else echo 'No';

//For compare the ending string with case sensitive. 
if(strpos(strrev($content), strrev($search)) === 0) echo 'Yes';
else echo 'No';

2

ไม่รู้ว่าเร็วไปหรือเปล่า แต่สำหรับการทดสอบอักขระเดี่ยวก็ใช้ได้เช่นกัน:

(array_pop(str_split($string)) === $test) ? true : false;
($string[strlen($string)-1] === $test) ? true : false;
(strrev($string)[0] === $test) ? true : false;


0

ฉันคิดว่าฟังก์ชันย้อนกลับเช่น strrchr () จะช่วยให้คุณจับคู่ส่วนท้ายของสตริงได้เร็วที่สุด


0

นี่คือบริสุทธิ์ PHP, ฟังก์ชั่นโดยไม่ต้องโทรภายนอกยกเว้นstrlen

function endsWith ($ends, $string)
{
    $strLength = strlen ($string);
    $endsLength = strlen ($ends);
    for ($i = 0; $i < $endsLength; $i++)
    {
        if ($string [$strLength - $i - 1] !== $ends [$i])
            return false;
    }
    return true;
}

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