Thử nghiệm hiệu quả nhất về việc một chuỗi PHP kết thúc bằng một chuỗi khác là gì?


125

Cách PHP tiêu chuẩn để kiểm tra xem một chuỗi $strkết thúc bằng một chuỗi con $testlà:

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

Đây có phải là cách nhanh nhất?



Bạn có thể tìm thấy s($str)->endsWith($test)hoặc s($str)->endsWithIgnoreCase($test)hữu ích, như được tìm thấy trong thư viện độc lập này .
caw

Câu trả lời:


152

Những gì Assaf nói là chính xác. Có một hàm dựng sẵn trong PHP để làm chính xác điều đó.

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

Nếu $testdài hơn $strPHP sẽ đưa ra cảnh báo, vì vậy bạn cần kiểm tra trước.

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

Đẹp. Có vẻ như việc so sánh tại chỗ sẽ nhanh hơn chất nền (), như Assaf đã chỉ ra.
Jason Cohen

2
Câu trả lời của mcrumley rất tuyệt, nhưng nên sử dụng '===' thay vì '=='. '===' nghiêm ngặt hơn và thường làm những gì bạn muốn, trong khi '==' có thể dẫn đến những bất ngờ khó chịu. Đoạn mã thứ ba của mcrumley là chính xác, nhưng hai đoạn mã đầu tiên thì không. struct_compare () trả về false trong một số trường hợp lỗi. Trong PHP, false == 0, vì vậy đoạn mã sẽ báo hiệu rằng chuỗi đã được tìm thấy. Với ===, điều này không xảy ra.
jcsahnwaldt phục hồi Monica

1
Tôi đã gặp một lỗi ngày hôm nay sẽ phá vỡ giải pháp mà bạn đã đưa ra từ PHP 5.5.11 trở đi. bug.php.net/orms.php?id=67043
user2180613

3 chức năng gọi qua đầu không làm cho nó nhanh nhất.
Thanh Trung

66

Phương pháp này tốn kém hơn một chút về bộ nhớ, nhưng nó nhanh hơn:

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

Điều này là tốt nhất khi bạn biết chính xác kim là gì, vì vậy bạn có thể mã cứng nó đảo ngược. Nếu bạn đảo ngược kim theo chương trình, nó sẽ trở nên chậm hơn so với phương pháp trước đó.


2
-1 Tôi thực sự nghi ngờ điều này nhanh hơn và nó khó khăn (tuyệt vời nhưng thường không hữu ích). Nếu haystack không kết thúc bằng kim, stripossẽ lặp lại toàn bộ chuỗi trong trường hợp xấu nhất trong khi đó substr_comparesẽ so sánh nhiều nhất với chiều dài của kim. Có, substr_compareyêu cầu tính toán độ dài của đống cỏ khô (và kim nhỏ hơn nhiều), nhưng phương pháp này yêu cầu sao chép nó đầy đủ, và có thể chuyển đổi toàn bộ vật thể thành chữ thường để khởi động.
David Harkness

cách tiếp cận tuyệt vời nhưng không hiệu quả (như đã đề cập trong câu trả lời) trong nhiều trường hợp! Vẫn là một upvote cho sự sáng tạo kỳ lạ và chứng minh rằng luôn có thể có nhiều cách làm điều tương tự mà bạn có thể tưởng tượng. Chúc mừng!
Fr0zenFyr

1
Tôi đã thử nghiệm và tìm thấy phương pháp này nhanh hơn câu trả lời được chấp nhận. Ngay cả khi cả cỏ khô và kim bị đảo ngược khi đang bay, nó vẫn nhanh hơn.
Shumoapp

@DavidHarkness Bạn đã kiểm tra xem liệu nghi ngờ của bạn có được bảo hành không?
Nathan

@Nathan Không, nó không đáng để dành thời gian để điểm chuẩn vì substr_compare()hoạt động tốt.
David Harkness

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

Độ lệch âm "bắt đầu đếm từ cuối chuỗi".


3
IMO đó là một trong những giải pháp tốt nhất được cung cấp
Roman Podlinov

+200 nếu tôi có thể. Cái nhìn sâu sắc quan trọng ở đây là việc sử dụng độ dài âm sẽ là phần cuối của chuỗi. Bạn cũng có thể sử dụng đế với độ dài -ve và thực hiện == so với $ test. Các câu trả lời khác là nghèo.
Nick

11

Đây là một cách đơn giản để kiểm tra xem một chuỗi có kết thúc bằng chuỗi khác hay không, bằng cách đưa ra strposmột phần bù ngay tại nơi cần tìm chuỗi:

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

Nói thẳng ra, và tôi nghĩ nó sẽ hoạt động trong PHP 4.


8

Nó phụ thuộc vào loại hiệu quả mà bạn quan tâm.

Phiên bản của bạn sử dụng nhiều bộ nhớ hơn do bản sao thêm từ việc sử dụng chất nền.

Một phiên bản thay thế có thể tìm kiếm chuỗi gốc cho lần xuất hiện cuối cùng của chuỗi con mà không tạo một bản sao, nhưng có lẽ sẽ chậm hơn do thử nghiệm nhiều hơn.

Có lẽ cách hiệu quả nhất là thực hiện vòng lặp char-by-char từ vị trí -sterlen (kiểm tra) cho đến hết chuỗi và so sánh. Đó là số lượng so sánh tối thiểu bạn có thể hy vọng thực hiện và hầu như không sử dụng thêm bộ nhớ.



3

Tôi hy vọng rằng câu trả lời dưới đây có thể hiệu quả và cũng đơn giản:

$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

Không biết điều này có nhanh hay không nhưng đối với một bài kiểm tra nhân vật, những công việc này cũng vậy:

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

1

cách dễ nhất để kiểm tra nó thông qua biểu thức thông thường

ví dụ để kiểm tra xem thư đã cho có phải là gmail không:

echo (preg_match("/@gmail\.com$/","example-email@gmail.com"))?'true':'false';

0

Tôi nghĩ rằng các hàm đảo ngược như strrchr () sẽ giúp bạn khớp phần cuối của chuỗi nhanh nhất.


0

Đây là PHP thuần túy, không gọi các hàm bên ngoài, ngoại trừ 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;
}

0

đối với kim đơn char:

if (@strrev($haystack)[0] == $needle) {
   // yes, it ends...
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.