Câu hỏi hàm startsWith () và endsWith () trong PHP


Làm thế nào tôi có thể viết hai hàm sẽ lấy một chuỗi và trả về nếu nó bắt đầu bằng ký tự / chuỗi được chỉ định hoặc kết thúc bằng nó?

Ví dụ:

$str = '|apples}';

echo startsWith($str, '|'); //Returns true
echo endsWith($str, '}'); //Returns true

1216
2018-05-07 12:14


gốc


Xem Laravel's Lớp Str startsWith () và endsWith () cho được thử nghiệm tốt phương pháp. Cạnh trường hợp đã gặp phải, do đó việc sử dụng rộng rãi mã này là một lợi thế. - Gras Double
Bạn có thể tìm thấy s($str)->startsWith('|') và s($str)->endsWith('}') hữu ích, như được tìm thấy trong thư viện độc lập này. - caw
Cảnh báo: hầu hết các câu trả lời ở đây không đáng tin cậy trong các mã hóa nhiều byte như UTF-8. - Álvaro González
Theo dõi nhận xét trên của tôi, bạn có thể đảm bảo sử dụng phiên bản mới nhất (tính đến hôm nay, 5,4). Đáng chú ý, startsWith () đã được tối ưu hóa cho các chuỗi haystack lớn. - Gras Double


Các câu trả lời:


function startsWith($haystack, $needle)
{
     $length = strlen($needle);
     return (substr($haystack, 0, $length) === $needle);
}

function endsWith($haystack, $needle)
{
    $length = strlen($needle);

    return $length === 0 || 
    (substr($haystack, -$length) === $needle);
}

Sử dụng điều này nếu bạn không muốn sử dụng regex.


1293
2018-05-07 12:24



+1 Điều này sạch hơn câu trả lời được chấp nhận. Cũng thế, $length không cần thiết trong dòng cuối cùng của endsWith(). - too much php
Tôi muốn nói endsWith ('foo', '') == false là hành vi đúng. Bởi vì foo không kết thúc với không có gì. 'Foo' kết thúc bằng 'o', 'oo' và 'Foo'. - MrHus
EndsWith có thể viết ngắn hơn rất nhiều: return substr($haystack, -strlen($needle))===$needle; - Rok Kralj
Bạn có thể tránh if hoàn toàn bằng cách vượt qua $length như tham số thứ ba substr: return (substr($haystack, -$length, $length);. Điều này xử lý trường hợp $length == 0 bằng cách trả về một chuỗi rỗng và không phải toàn bộ $haystack. - mxk
@MrHus Tôi khuyên bạn nên sử dụng các chức năng an toàn đa byte, ví dụ: mb_strlen và mb_substr - 19Gerhard85


Có thể sử dụng strrpos và strpos để kiểm tra lần lượt bắt đầu và kết thúc.

Lưu ý rằng việc sử dụng strrpos để kiểm tra bắt đầu bằng và strpos để kiểm tra kết thúc bằng sẽ trở lại càng sớm càng tốt thay vì kiểm tra toàn bộ chuỗi cho đến khi kết thúc. Ngoài ra, giải pháp này không tạo ra một chuỗi tạm thời. Cân nhắc giải thích lý do trước khi downvoting. Chỉ vì một f-wit tại DWTF không hiểu cách chức năng này hoạt động hoặc nghĩ rằng chỉ có một giải pháp không có nghĩa là câu trả lời này là sai.

function startsWith($haystack, $needle) {
    // search backwards starting from haystack length characters from the end
    return $needle === ''
      || strrpos($haystack, $needle, -strlen($haystack)) !== false;
}

function endsWith($haystack, $needle) {
    // search forward starting from end minus needle length characters
    if ($needle === '') {
        return true;
    }
    $diff = \strlen($haystack) - \strlen($needle);
    return $diff >= 0 && strpos($haystack, $needle, $diff) !== false;
}

Kiểm tra và kết quả (so sánh với điều này):

startsWith('abcdef', 'ab') -> true
startsWith('abcdef', 'cd') -> false
startsWith('abcdef', 'ef') -> false
startsWith('abcdef', '') -> true
startsWith('', 'abcdef') -> false

endsWith('abcdef', 'ab') -> false
endsWith('abcdef', 'cd') -> false
endsWith('abcdef', 'ef') -> true
endsWith('abcdef', '') -> true
endsWith('', 'abcdef') -> false

Lưu ý: các strncmp và substr_compare chức năng sẽ hoạt động tốt hơn chức năng này.


937
2018-05-06 18:22



Câu trả lời này đã đưa nó vào WTF hàng ngày! : D Xem thedailywtf.com/articles/… - Wim ten Brink
Xin lưu ý rằng nhận xét @DavidWallace và @FrancescoMM áp dụng cho phiên bản cũ của câu trả lời này. Câu trả lời hiện tại sử dụng strrpos mà (nên) thất bại ngay lập tức nếu kim không phù hợp với sự khởi đầu của haystack. - Salman A
Tôi không hiểu. Dựa trên php.net/manual/en/function.strrpos.php: "Nếu giá trị là số âm, thay vào đó, tìm kiếm sẽ bắt đầu từ nhiều ký tự đó từ cuối chuỗi, tìm kiếm ngược lại". Điều này dường như chỉ ra rằng chúng ta đang bắt đầu từ ký tự 0 (do -strlength($haystack)) và tìm kiếm lạc hậu từ đó? Điều đó có nghĩa là bạn không tìm kiếm gì? Tôi cũng không hiểu !== false các phần của điều này. Tôi đoán đây là dựa trên một quirk của PHP, nơi một số giá trị là "truthy" và những người khác "falsy" nhưng làm thế nào mà làm việc trong trường hợp này? - Welbog
@Welbog: ví dụ haystack = xxxyyy kim = yyy và sử dụng strrpos tìm kiếm bắt đầu từ lần đầu tiên x. Bây giờ chúng ta không có một trận đấu thành công ở đây (tìm thấy x thay vì y) và chúng ta không thể đi ngược lại nữa (chúng ta đang ở đầu chuỗi) tìm kiếm thất bại ngay. Về việc sử dụng !== false - - strrpos trong ví dụ trên sẽ trả về 0 hoặc sai và không phải giá trị khác. Tương tự như vậy, strpos trong ví dụ trên có thể trở lại $temp (vị trí dự kiến) hoặc sai. Tôi đã đi với !== false cho sự nhất quán nhưng bạn có thể sử dụng === 0 và === $temp trong các hàm tương ứng. - Salman A
@spoo nó đã được thành lập rằng strpos === 0 là một giải pháp khủng khiếp nếu haystack là lớn và kim không tồn tại. - Salman A


Cập nhật ngày 23 tháng 8 năm 2016

Chức năng

function substr_startswith($haystack, $needle) {
    return substr($haystack, 0, strlen($needle)) === $needle;
}

function preg_match_startswith($haystack, $needle) {
    return preg_match('~' . preg_quote($needle, '~') . '~A', $haystack) > 0;
}

function substr_compare_startswith($haystack, $needle) {
    return substr_compare($haystack, $needle, 0, strlen($needle)) === 0;
}

function strpos_startswith($haystack, $needle) {
    return strpos($haystack, $needle) === 0;
}

function strncmp_startswith($haystack, $needle) {
    return strncmp($haystack, $needle, strlen($needle)) === 0;
}

function strncmp_startswith2($haystack, $needle) {
    return $haystack[0] === $needle[0]
        ? strncmp($haystack, $needle, strlen($needle)) === 0
        : false;
}

Kiểm tra

echo 'generating tests';
for($i = 0; $i < 100000; ++$i) {
    if($i % 2500 === 0) echo '.';
    $test_cases[] = [
        random_bytes(random_int(1, 7000)),
        random_bytes(random_int(1, 3000)),
    ];
}
echo "done!\n";


$functions = ['substr_startswith', 'preg_match_startswith', 'substr_compare_startswith', 'strpos_startswith', 'strncmp_startswith', 'strncmp_startswith2'];
$results = [];

foreach($functions as $func) {
    $start = microtime(true);
    foreach($test_cases as $tc) {
        $func(...$tc);
    }
    $results[$func] = (microtime(true) - $start) * 1000;
}

asort($results);

foreach($results as $func => $time) {
    echo "$func: " . number_format($time, 1) . " ms\n";
}

Kết quả (PHP 7.0.9)

(Sắp xếp nhanh nhất đến chậm nhất)

strncmp_startswith2: 40.2 ms
strncmp_startswith: 42.9 ms
substr_compare_startswith: 44.5 ms
substr_startswith: 48.4 ms
strpos_startswith: 138.7 ms
preg_match_startswith: 13,152.4 ms

Kết quả (PHP 5.3.29)

(Sắp xếp nhanh nhất đến chậm nhất)

strncmp_startswith2: 477.9 ms
strpos_startswith: 522.1 ms
strncmp_startswith: 617.1 ms
substr_compare_startswith: 706.7 ms
substr_startswith: 756.8 ms
preg_match_startswith: 10,200.0 ms

startswith_benchmark.php


217
2017-08-24 00:07



Nếu các chuỗi không trống, như trong các bài kiểm tra của bạn, điều này thực sự bằng cách nào đó (20-30%) nhanh hơn: function startswith5b($haystack, $needle) {return ($haystack{0}==$needle{0})?strncmp($haystack, $needle, strlen($needle)) === 0:FALSE;} Tôi đã thêm trả lời dưới đây. - FrancescoMM
@ Jronny Bởi vì 110 là ít hơn 133 ... ?? - mpen
Darn, tôi không biết những gì đã đi đến đầu của tôi thời gian đó. Prolly thiếu ngủ. - Jronny
@mpen, tôi nhận thấy không phải là con voi ở tất cả :( - Visman
$haystack[0] sẽ ném một thông báo lỗi nếu bạn không kiểm tra nó với isset. Tương tự cho kim tiêm. Nhưng nếu bạn thêm thử nghiệm, nó sẽ làm chậm hiệu suất của nó - Thanh Trung


Tất cả các câu trả lời cho đến nay dường như làm rất nhiều công việc không cần thiết, strlen calculations, string allocations (substr), v.v. 'strpos' và 'stripos' hàm trả về chỉ số của lần xuất hiện đầu tiên của $needle trong $haystack:

function startsWith($haystack,$needle,$case=true)
{
    if ($case)
        return strpos($haystack, $needle, 0) === 0;

    return stripos($haystack, $needle, 0) === 0;
}

function endsWith($haystack,$needle,$case=true)
{
    $expectedPosition = strlen($haystack) - strlen($needle);

    if ($case)
        return strrpos($haystack, $needle, 0) === $expectedPosition;

    return strripos($haystack, $needle, 0) === $expectedPosition;
}

127
2018-05-13 21:23



endsWith() chức năng có lỗi. Dòng đầu tiên của nó phải là (không có -1): $expectedPosition = strlen($haystack) - strlen($needle); - Enrico Detoma
Điều strlen () không cần thiết. Trong trường hợp chuỗi không bắt đầu bằng kim đã cho thì mã ur sẽ không cần thiết quét toàn bộ haystack. - AppleGrew
@Mark yea, kiểm tra chỉ là bắt đầu là một LOT nhanh hơn, đặc biệt là nếu bạn đang làm một cái gì đó như kiểm tra các loại MIME (hoặc bất kỳ nơi nào khác nơi chuỗi được ràng buộc là lớn) - chacham15
@mark Tôi đã làm một số tiêu chuẩn với 1000 char haystack và 10 hoặc 800 char kim và strpos là 30% nhanh hơn. Làm tiêu chuẩn của bạn trước khi nói rằng một cái gì đó là nhanh hơn hay không ... - wdev
Bạn nên cân nhắc việc trích dẫn kim như strpos($haystack, "$needle", 0) Nếu có bất kì cơ hội nó chưa phải là một chuỗi (ví dụ, nếu nó đến từ json_decode()). Nếu không, hành vi mặc định [lẻ] của strpos() có thể gây ra kết quả không mong muốn: "Nếu kim không phải là một chuỗi, nó được chuyển thành một số nguyên và được áp dụng như giá trị thứ tự của một ký tự." - user113215


function startsWith($haystack, $needle, $case = true) {
    if ($case) {
        return (strcmp(substr($haystack, 0, strlen($needle)), $needle) === 0);
    }
    return (strcasecmp(substr($haystack, 0, strlen($needle)), $needle) === 0);
}

function endsWith($haystack, $needle, $case = true) {
    if ($case) {
        return (strcmp(substr($haystack, strlen($haystack) - strlen($needle)), $needle) === 0);
    }
    return (strcasecmp(substr($haystack, strlen($haystack) - strlen($needle)), $needle) === 0);
}

Tín dụng để:

Kiểm tra xem chuỗi có kết thúc bằng chuỗi khác không

Kiểm tra xem chuỗi có bắt đầu bằng chuỗi khác không


45
2018-05-07 12:15



strtolower không phải là cách tốt nhất để tạo ra các hàm phân biệt chữ hoa chữ thường. Trong một số miền địa phương, vỏ phức tạp hơn là chỉ trên và dưới. - Sander Rijken
Tôi thấy phàn nàn và không có giải pháp ... Nếu bạn sẽ nói rằng nó xấu, sau đó bạn nên đưa ra một ví dụ về nó như thế nào là tốt. - KdgDev
@WebDevHobo: đó là lý do tại sao tôi thêm một câu trả lời bản thân mình một ngày trước khi bình luận của bạn. Đối với mã của bạn strcasecmp thực sự là điều phải làm. - Sander Rijken
@Click_Upvote bạn nên mua WebDev bia: v - almosnow


Các chức năng regex ở trên, nhưng với các tinh chỉnh khác cũng đề xuất ở trên:

 function startsWith($needle, $haystack) {
     return preg_match('/^' . preg_quote($needle, '/') . '/', $haystack);
 }

 function endsWith($needle, $haystack) {
     return preg_match('/' . preg_quote($needle, '/') . '$/', $haystack);
 }

24
2018-06-19 16:11



trong php cho hoạt động chuỗi thứ tự của các tham số là $ haystack, $ kim. các hàm này ngược lại và hoạt động như các hàm mảng trong đó thứ tự thực sự là $ kim, $ haystack. - Andrew Anthony Gerst


Nếu tốc độ là quan trọng đối với bạn, hãy thử điều này. (Tôi tin rằng đó là phương pháp nhanh nhất)

Chỉ hoạt động cho chuỗi và nếu $ haystack chỉ có 1 ký tự

function startsWithChar($needle, $haystack)
{
   return ($needle[0] === $haystack);
}

function endsWithChar($needle, $haystack)
{
   return ($needle[strlen($needle) - 1] === $haystack);
}

$str='|apples}';
echo startsWithChar($str,'|'); //Returns true
echo endsWithChar($str,'}'); //Returns true
echo startsWithChar($str,'='); //Returns false
echo endsWithChar($str,'#'); //Returns false

21
2017-12-15 08:53



đây có lẽ là câu trả lời hiệu quả nhất bởi vì không sử dụng bất kỳ chức năng nào như chuỗi phụ, chuỗi thông thường ...
Nó có thể sẽ kiểm tra xem chuỗi có ít nhất một ký tự và có hai tham số được hoán đổi hay không - a1an
Sáng tạo. Kim có chứa đống cỏ khô. BTW có một số waning xấu xí với: endsWithChar('','x'), nhưng kết quả là chính xác - Tino


Tôi nhận thấy điều này đã được hoàn thành, nhưng bạn có thể muốn xem xét strncmp vì nó cho phép bạn đặt chiều dài của chuỗi để so sánh, vì vậy:

function startsWith($haystack, $needle, $case=true) {
    if ($case)
        return strncasecmp($haystack, $needle, strlen($needle)) == 0;
    else
        return strncmp($haystack, $needle, strlen($needle)) == 0;
}    

15
2017-09-17 02:50



làm thế nào bạn sẽ kết thúc với điều này? - mpen
@Mark - bạn có thể nhìn vào câu trả lời được chấp nhận, nhưng tôi thích sử dụng strncmp chủ yếu là vì tôi nghĩ rằng nó là an toàn hơn. - James Black
Ý tôi là với strncmp. Bạn không thể chỉ định một offset. Điều đó có nghĩa là hàm endsWith của bạn sẽ phải sử dụng một phương thức hoàn toàn khác. - mpen
@Mark - Đối với endsWith tôi sẽ chỉ sử dụng strrpos (php.net/manual/en/function.strrpos.php), nhưng, nói chung, bất cứ lúc nào bạn sử dụng strcmp strncmp có lẽ là một lựa chọn an toàn hơn. - James Black


Dưới đây là hai chức năng không giới thiệu một chuỗi tạm thời, có thể hữu ích khi kim rất lớn:

function startsWith($haystack, $needle)
{
    return strncmp($haystack, $needle, strlen($needle)) === 0;
}

function endsWith($haystack, $needle)
{
    return $needle === '' || substr_compare($haystack, $needle, -strlen($needle)) === 0;
}

15
2017-08-02 07:40



+1 Hoạt động từ PHP5.1 và IMHO câu trả lời hay nhất. Nhưng endsWidth nên làm return $needle==='' || substr_compare(... vì vậy nó hoạt động như mong đợi -strlen($needle)===0 mà không cần sửa chữa endsWith('a','') trở về false - Tino
@Tino Cảm ơn ... Tôi cảm thấy đó là một lỗi trong substr_compare() thực sự, vì vậy tôi đã thêm PR để sửa lỗi đó :) - Ja͢ck
Cuộc gọi endsWith('', 'foo') kích hoạt Cảnh báo: “substr_compare (): Vị trí bắt đầu không thể vượt quá độ dài chuỗi ban đầu”. Có lẽ đó là một lỗi khác trong substr_compare()nhưng để tránh nó, bạn cần kiểm tra trước ...|| (strlen($needle) <= strlen($haystack) && substr_compare(...) === 0); - gx_
@gx_ Không cần phải chậm lại với nhiều mã hơn. Chỉ dùng return $needle === '' || @substr_compare(.. để ngăn chặn cảnh báo này. - Tino


Câu hỏi này đã có nhiều câu trả lời, nhưng trong một số trường hợp, bạn có thể giải quyết cho một cái gì đó đơn giản hơn tất cả chúng. Nếu chuỗi bạn đang tìm kiếm được biết (mã hoá cứng), bạn có thể sử dụng cụm từ thông dụng mà không có bất kỳ trích dẫn nào, v.v.

Kiểm tra xem chuỗi có bắt đầu bằng 'ABC' hay không:

preg_match('/^ABC/', $myString); // "^" here means beginning of string

kết thúc bằng 'ABC':

preg_match('/ABC$/', $myString); // "$" here means end of string

Trong trường hợp đơn giản của tôi, tôi muốn kiểm tra xem một chuỗi có kết thúc bằng dấu gạch chéo hay không:

preg_match('/\/$/', $myPath);   // slash has to be quoted

Lợi thế: vì nó rất ngắn và đơn giản, bạn không cần phải định nghĩa một hàm (chẳng hạn như endsWith()) như được trình bày ở trên.

Nhưng một lần nữa - đây không phải là giải pháp cho mọi trường hợp, chỉ là một điều rất cụ thể.


13
2018-01-06 08:59



bạn không cần phải mã cứng chuỗi. regex có thể năng động. - Ryan McCullagh
@self đúng, nhưng nếu chuỗi không phải là hardcoded, bạn phải thoát khỏi nó. Hiện tại có 2 câu trả lời cho câu hỏi này. Điều này là dễ dàng, nhưng nó phức tạp mã chỉ một chút. Vì vậy, quan điểm của tôi là đối với các trường hợp rất đơn giản, nơi có thể viết mã cứng, bạn có thể giữ nó đơn giản. - noamtm


Bạn có thể dùng strpos và strrpos 

$bStartsWith = strpos($sHaystack, $sNeedle) == 0;
$bEndsWith = strrpos($sHaystack, $sNeedle) == strlen($sHaystack)-strlen($sNeedle);

10
2018-05-12 12:36



Nếu bạn đang sử dụng ba bằng ở đây strpos($sHaystack, $sNeedle) == 0 như thế này strpos($sHaystack, $sNeedle) === 0? Tôi thấy một lỗi, khi false == 0 đánh giá true. - Kalyan