Bir PHP dizesinin başka bir dizeyle bitip bitmediğine dair en etkili test nedir?


Yanıtlar:


152

Assaf'ın söylediği doğru. PHP'de tam olarak bunu yapmak için yerleşik bir işlev vardır.

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

Eğer $testdaha uzun olduğunu $ströncelikle o için kontrol edilmesi gereken böylece, bir uyarı verecektir PHP.

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

Güzel. Assaf'ın da belirttiği gibi, yerinde karşılaştırma yapmak substr () 'den daha hızlı olacak gibi görünüyor.
Jason Cohen

2
mcrumley'in cevabı güzel, ancak '==' yerine '===' kullanmalı. '===' daha katıdır ve genellikle istediğinizi yapar, '==' ise kötü sürprizlere yol açabilir. mcrumley'in üçüncü kod pasajı doğru, ancak ilk ikisi değil. substr_compare (), bazı hata durumlarında yanlış döndürür. PHP'de false == 0, bu nedenle kod parçacıkları dizenin bulunduğunu bildirir. === ile bu olmaz.
jcsahnwaldt Reinstate Monica

1
Bugün PHP 5.5.11 ve sonrasında verdiğiniz çözümü bozacak bir hatayla karşılaştım. bugs.php.net/bug.php?id=67043
user2180613

3 işlev çağrısı ek yükü bunu en hızlı yapmaz.
Thanh Trung

66

Bu yöntem bellek açısından biraz daha pahalıdır, ancak daha hızlıdır:

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

Bu, iğnenin tam olarak ne olduğunu bildiğiniz zaman en iyisidir, böylece tersini kodlayabilirsiniz. İğneyi programlı olarak ters çevirirseniz, önceki yöntemden daha yavaş hale gelir.


2
-1 Bunun daha hızlı olduğundan ciddi olarak şüpheliyim ve aldatıcı (havalı ama genellikle yardımcı olmuyor). Samanlık Eğer gelmez iğne ile sona, striposoysa en kötü durumda tüm dizeyi yineleme olacak substr_compareen fazla iğnenin uzunluğu karşılaştırır. Evet substr_compareot yığını (ve daha küçük iğne) uzunluğunun hesaplanmasını gerektirmektedir, ancak bu yöntem gerektirir ve tam olarak kopyalama ve muhtemelen çizme için küçük harf içine tüm bir şey dönüştürülmesi.
David Harkness

havalı bir yaklaşım ama yetersiz (cevabın kendisinde belirtildiği gibi) çoğu durumda! Yine de garip bir şekilde yaratıcı olmak ve aynı şeyi yapmanın hayal edebileceğinizden daha fazla yolu olabileceğini göstermek için bir olumlu oy. Şerefe!
Fr0zenFyr

1
Bu yöntemi test ettim ve kabul edilen cevaptan daha hızlı buldum. Hem samanlık hem de iğne anında tersine dönse bile, daha hızlıdır.
Shumoapp

@DavidHarkness Şüphelerinizin garanti edilip edilmediğini test ettiniz mi?
Nathan

@Nathan Hayır, iyi substr_compare()çalıştığı için kıyaslama yapmak için zaman ayırmaya değmez .
David Harkness

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

Negatif uzaklık "dizenin sonundan saymaya başlar".


3
IMO, sunulan çözümlerin en iyilerinden biri
Roman Podlinov

Yapabilseydim +200. Buradaki temel fikir, negatif bir uzunluk kullanmanın dizenin son kısmını almasıdır. Ayrıca -ve uzunluğunda substr kullanabilir ve $ testine karşı bir == yapabilirsiniz. Diğer cevaplar zayıf.
Nick

11

Dizenin strpostam olarak bulunması gereken yerde bir uzaklık vererek bir dizenin diğeriyle bitip bitmediğini kontrol etmenin basit bir yolu :

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

Anlaşılır ve bunun PHP 4'te çalışacağını düşünüyorum.


8

Ne tür bir verimliliği önemsediğinize bağlıdır.

Alt sürüm kullanımından kaynaklanan fazladan kopya nedeniyle sürümünüz daha fazla bellek kullanıyor.

Alternatif bir sürüm, bir kopya yapmadan alt dizenin son geçtiği yer için orijinal dizeyi arayabilir, ancak daha fazla test nedeniyle muhtemelen daha yavaş olacaktır.

Muhtemelen en etkili yol, -sterlen (test) konumundan dizginin sonuna kadar karakter başına döngü yapmak ve karşılaştırmaktır. Bu, yapmayı umabileceğiniz minimum karşılaştırma miktarıdır ve kullanılan fazladan bellek neredeyse yoktur.


5

Başka bir yol da strrposişlevi kullanmak olabilir :

strrpos($str, $test) == strlen($str) - strlen($test)

Ama bu daha hızlı değil.


3

Umarım aşağıdaki cevap etkili ve aynı zamanda basit olabilir:

$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

Bunun hızlı olup olmadığını bilmiyorum ama tek bir karakter testi için bunlar da işe yarar:

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

1

düzenli ifadeyle kontrol etmenin en kolay yolu

örneğin verilen postanın gmail olup olmadığını kontrol etmek için :

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

0

Strrchr () gibi ters işlevlerin dizenin sonunu en hızlı şekilde eşleştirmenize yardımcı olacağını düşünüyorum.


0

Bu, strlen dışında harici işlevleri çağırmadan saf PHP'dir .

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

tek karakterli iğne için:

if (@strrev($haystack)[0] == $needle) {
   // yes, it ends...
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.