PHP文字列が別の文字列で終わるかどうかの最も効率的なテストは何ですか?


125

$str文字列$testが部分文字列で終わるかどうかをテストする標準のPHPの方法は次のとおりです。

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

これは最速の方法ですか?



このスタンドアロンライブラリにあるように、あなたは見つけs($str)->endsWith($test)たり、s($str)->endsWithIgnoreCase($test)役立つかもしれません。
2016

回答:


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;
}

いいね。Assafが指摘したように、インプレースでの比較はsubstr()よりも高速なようです。
Jason Cohen

2
mcrumleyの答えはすばらしいですが、「==」の代わりに「===」を使用する必要があります。「===」はより厳密で通常は必要なことを実行しますが、「==」は意外な驚きにつながる可能性があります。mcrumleyの3番目のコードスニペットは正しいですが、最初の2つは正しくありません。substr_compare()は、一部のエラーの場合にfalseを返します。PHPではfalse == 0なので、コードスニペットは文字列が見つかったことを通知します。===では、これは起こりません。
jcsahnwaldt Reinstate Monica、

1
今日、バグに遭遇しました。このバグにより、PHP 5.5.11以降から提供されたソリューションが壊れます。bugs.php.net/bug.php?id=67043
user2180613 14

3つの関数呼び出しのオーバーヘッドは、最速にはなりません。
Thanh Trung

66

この方法はメモリを少し消費しますが、高速です。

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

これは、針が何であるかを正確に理解している場合に最適であり、逆にハードコードすることができます。プログラムで針を逆にすると、以前の方法よりも遅くなります。


2
-1私はこれがより速いことを真剣に疑っています、そしてそれはトリッキーです(クールですが通常は役に立ちません)。干し草の山針で終わっていないstripos場合、最悪の場合は文字列全体を反復しますが、最大でsubstr_compare針の長さを比較します。はい、substr_compare干し草の山(およびはるかに小さい針)の長さを計算する必要がありますが、この方法ではそれを完全にコピーし、場合によっては全体を小文字に変換して起動する必要があります。
David Harkness

クールなアプローチですが、多くの場合(回答自体で述べたように)非効率的です!奇妙に創造的であり、あなたが想像することと同じことをするためのより多くの方法が常にあり得ることを実証することへの賛成票はまだあります。乾杯!
Fr0zenFyr

1
私はこの方法をテストし、受け入れられた答えよりも速く見つけました。干し草の山と針の両方がその場で反転されても、それはより高速です。
Shumoapp、2018

@DavidHarkness疑いが正当化されるかどうかを確認するためにテストしましたか?
ネイサン

@ネイサンいいえ、substr_compare()うまく機能するため、ベンチマークする価値はありません。
David Harkness

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

負のオフセットは、「文字列の終わりからカウントを開始します」。


3
IMO提供されたソリューションの中で最高の1つです
Roman Podlinov '22

できれば+200。ここで重要な洞察は、負の長さを使用すると、文字列の最後の部分が取得されるということです。-veの長さを指定してsubstrを使用し、$ testに対して==を実行することもできます。他の答えは貧弱です。
Nick、

11

strpos文字列が見つかるはずの場所にオフセットを与えることで、ある文字列が別の文字列で終わるかどうかを確認する簡単な方法を次に示します。

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

簡単です。これはPHP 4で機能すると思います。


8

それはあなたが気にかける効率の種類に依存します。

substrの使用による余分なコピーにより、バージョンはより多くのメモリを使用します。

別のバージョンでは、コピーを作成せずに、元の文字列で最後に出現した部分文字列を検索する場合がありますが、テストの回数が増えるため、速度が低下する可能性があります。

おそらく最も効率的な方法は、-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;

1

正規表現で確認する最も簡単な方法

たとえば、与えられたメールがgmailであるかどうかを確認するには:

echo (preg_match("/@gmail\.com$/","example-email@gmail.com"))?'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.