PHPのstartsWith()およびendsWith()関数


1481

文字列を受け取り、指定された文字/文字列で始まるか、それで終わる場合に戻る2つの関数をどのように記述できますか?

例えば:

$str = '|apples}';

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

19
十分にテストされたメソッドについては、LaravelのStrクラスの startsWith()およびendsWith()を参照してください。エッジケースが発生したため、このコードを広く使用することには利点があります。
Gras Double

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

3
警告:ここでのほとんどの回答は、UTF-8などのマルチバイトエンコーディングでは信頼できません。
アルバロゴンザレス

上記の私のコメントに続き、最新バージョン(本日現在、5.4)を使用するようにしてください。特に、startsWith()は大規模な干し草の文字列用に最適化されています。
Gras Double、

回答:


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

function endsWith($haystack, $needle)
{
    $length = strlen($needle);
    if ($length == 0) {
        return true;
    }

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

正規表現を使用したくない場合に使用します。


16
+1これは受け入れられた答えよりもきれいです。また、$lengthの最後の行では不要ですendsWith()
phpが多すぎる

13
私は、endsWith( 'foo'、 '')== falseが正しい動作だと思います。fooは何も終わらないからです。「Foo」は「o」、「oo」、「Foo」で終わります。
MrHus 2012

125
EndsWithはもっと短く書くことができます:return substr($haystack, -strlen($needle))===$needle;
Rok Kralj

12
3番目のパラメータとして:にif渡すことで、完全に回避でき$lengthます。これは、全体ではなく空の文字列を返すことでケースを処理します。substrreturn (substr($haystack, -$length, $length);$length == 0$haystack
mxxk 2015年

20
@MrHus mb_strlenやmb_substrなどのマルチバイトセーフ関数の使用をお勧めします
19Gerhard85

1024

substr_compare関数を使用して、start-withおよびend-withをチェックできます。

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

これは、PHP 7(ベンチマークスクリプト)の最速のソリューションの1つです。8KBの干し草の山、さまざまな長さの針、完全一致、部分一致、一致なしのケースに対してテストされています。strncmpstarts-withの方が少し高速ですが、ends-withをチェックできません。


74
この答えがデイリーWTFになりました!:Dthedailywtf.com/articles/…を
ウィムテンブリンク

@DavidWallaceと@FrancescoMMのコメントは、この回答の古いバージョンに適用されることに注意してください。現在の答えはstrrpos、needleがhaystackの先頭に一致しない場合、すぐに失敗する(すべき)を使用しています。
Salman A

2
わかりません。基づいてphp.net/manual/en/function.strrpos.php:「値が負の場合、検索ではなく、後方を検索、文字列の末尾からその文字数から開始します。」これは、文字0(のため-strlength($haystack))から開始し、そこから後方検索していることを示しているようです。それはあなたが何も検索していないという意味ではありませんか?!== falseこの部分も分からない。これは、いくつかの値が「真実」で他の値が「偽」であるPHPの癖に依存していると思いますが、この場合、どのように機能しますか?
Welbog

3
@Welbog:たとえば、haystack = xxxyyyneedle = yyystrrpos、検索の使用は最初のから始まりxます。ここで、一致は成功せず(yの代わりにxが見つかりました)、もう戻ることはできません(文字列の先頭にあります)。検索はすぐに失敗ます。上記の例で!== false- strrposを使用すると、0またはfalseが返され、他の値は返されません。同様strposに、上記の例では$temp(期待される位置)またはfalseを返すことができます。私は一緒に行った!== false一貫性のためではなく、あなたが使用することができます=== 0し、=== $tempそれぞれの機能インチ
Salman A

8
@spoo haystackが大きく、needleが存在しない場合、strpos === 0はひどい解決策であることがすでに確立されています。
Salman A

243

2016年8月23日更新

機能

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

テスト

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

結果(PHP 7.0.9)

(最も速いものから最も遅いものへのソート)

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

結果(PHP 5.3.29)

(最も速いものから最も遅いものへのソート)

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


3
テストのように文字列が空でない場合、これは実際には何とか(20〜30%)高速ですfunction startswith5b($haystack, $needle) {return ($haystack{0}==$needle{0})?strncmp($haystack, $needle, strlen($needle)) === 0:FALSE;}。以下に返信を追加しました。
FrancescoMM

3
@Jronny 110は133より小さいので... ??
mpen

2
くそー、その時何が頭にあったのかわからない。おおむね睡眠不足。
Jronny、2014

1
@mpen、私はすべて:(で象ない気づいた
Visman

1
これらのテストは、パフォーマンスのテストには適していません。あなたがやっていることは、針としてランダムな文字列を使用しています。99.99%のケースでは一致はありません。ほとんどの関数は、最初のバイトに一致した後に終了します。一致が見つかった場合はどうですか?マッチが成功するまでの時間が最も短い関数はどれですか。針の99%は一致するが、最後の数バイトは一致しない場合はどうですか?一致しないと結論付けるのに最も時間がかかる関数はどれですか。
Salman A

137

すべての答えは、これまでの不必要な作業の負荷を行うように見える、strlen calculationsstring allocations (substr)、などのザ・'strpos'および'stripos'機能は、最初の発生のインデックスを返す$needleでは$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;
}

2
endsWith()関数にエラーがあります。その最初の行は(-1なし)でなければなりません:$expectedPosition = strlen($haystack) - strlen($needle);
Enrico Detoma

6
strlen()は不要ではありません。文字列が指定された針で始まらない場合、コードは干し草の山全体を不必要にスキャンします。
AppleGrew、2011年

5
@マークはい、特にMIMEタイプ(または文字列が大きくバインドされている他の場所)をチェックするような場合は特に、最初だけをチェックする方がLOTで高速になります
chacham15

2
@mark私はいくつかのベンチマークを1000文字の干し草と10または800文字の針で行い、strposは30%高速でした。何かが速いかどうかを述べる前にベンチマークを実行してください...
wdev

7
あなたは強くように針を引用検討すべきでstrpos($haystack, "$needle", 0)あるかどう任意の(それはから来ていた場合、例えばチャンスがすでに文字列ではありませんjson_decode())。そうしないと、[odd]のデフォルトの動作strpos()により予期しない結果が生じる可能性があります: " needleが文字列でない場合、整数に変換され、文字の序数値として適用されます。 "
quietmint

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

クレジット

文字列が別の文字列で終わるかどうかを確認する

文字列が別の文字列で始まるかどうかを確認する


1
strtolowerは、大文字と小文字を区別しない関数を作成する最良の方法ではありません。一部のロケールでは、大文字と小文字だけでなく、大文字と小文字の組み合わせが複雑になります。
サンダーライケン2009年

8
文句を言うが解決策はない...あなたがそれが悪いと言うつもりなら、あなたはそれがどうあるべきかの例を与えるべきです。
KdgDev 2009年

2
@WebDevHobo:そのため、コメントの前日に自分で回答を追加しました。あなたのコードでは、strcasecmpは実際に正しいことでした。
サンダーライケン

29

上記の正規表現は機能しますが、他の調整も上記で提案されています:

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

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

2
PHPの文字列操作では、パラメーターの順序は$ haystack、$ needleです。これらの関数は後方にあり、配列が実際に$ needle、$ haystackである配列関数のように機能します。
アンディ

29

この質問にはすでに多くの答えがありますが、場合によっては、すべての質問よりも簡単なことで解決できます。探している文字列がわかっている(ハードコードされている)場合は、引用符なしで正規表現を使用できます。

文字列が「ABC」で始まるかどうかを確認します。

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

「ABC」で終わる:

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

私の単純なケースでは、文字列がスラッシュで終わっているかどうかを確認したいと思いました。

preg_match('#/$#', $myPath);   // Use "#" as delimiter instead of escaping slash

利点:非常に短くてシンプルなので、endsWith()上記のように関数(など)を定義する必要はありません。

しかし、これもまた、すべての場合の解決策ではなく、非常に具体的なものです。


文字列をハードコーディングする必要はありません。正規表現動的にすることできます。
ライアン

2
@self trueですが、文字列がハードコーディングされていない場合は、エスケープする必要があります。現在、この質問には2つの回答があります。これは簡単ですが、コードが少し複雑になります。だから私の指摘は、ハードコーディングが可能な非常に単純なケースでは、それを単純に保つことができるということでした。
noamtm 2016年

1
また、スラッシュをエスケープする必要はありません。@スラッシュ(/)をエスケープする必要がないように、正規表現をのような他の文字で囲むことができます。例3のphp.net/manual/en/function.preg-match.phpを参照してください。
cjbarth 2018年

@cjbarthに感謝します。それに応じて私の答えを変更しました。ところで、「#」はスラッシュを処理するときにphp.net/manual/en/regexp.reference.delimiters.phpで指定された例です。
noamtm 2018年

23

速度が重要な場合は、これを試してください(これが最速の方法だと思います)。

文字列に対してのみ機能し、$ haystackが1文字のみの場合

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

1
余分として任意の関数、ちょうど通常の文字列を使用していないので、これは...おそらく最も効率的な答えである

文字列は、少なくとも一つの文字があり、スワップ2つのパラメータを持っている場合、それは可能性がチェックする必要があります
a1an

1
クリエイティブ。干し草の山を含む針。ところで、いくつかの醜い衰退があります:endsWithChar('','x')、しかし結果は正しいです
Tino

18

一時的な文字列を導入しない2つの関数を次に示します。これは、針がかなり大きい場合に役立ちます。

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

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

2
+1はPHP5.1以降で機能し、IMHOがベストアンサーです。しかし、endsWidth行う必要がありますreturn $needle==='' || substr_compare(...それがために期待どおりに動作-strlen($needle)===0、修正せずに、どの作るendsWith('a','')リターンfalse
ティノ

@Tinoおかげで...私はそれはバグだと感じsubstr_compare()、私が追加したので、実際にPRを修正すること:)
ジャック

3
呼び出しendsWith('', 'foo')は警告をトリガーします:「substr_compare():開始位置は最初の文字列の長さを超えることはできません」。多分それはの別のバグかもしれませsubstr_compare()んが、それを回避するには、次のような事前チェックが必要です|| (strlen($needle) <= strlen($haystack) && substr_compare(... ...) === 0);
gx_

@gx_より多くのコードで減速する必要はありません。return $needle === '' || @substr_compare(この警告を抑制するには、..を使用するだけです。
ティノ

17

最速のendsWith()ソリューション:

# Checks if a string ends in a string
function endsWith($haystack, $needle) {
    return substr($haystack,-strlen($needle))===$needle;
}

基準:

# This answer
function endsWith($haystack, $needle) {
    return substr($haystack,-strlen($needle))===$needle;
}

# Accepted answer
function endsWith2($haystack, $needle) {
    $length = strlen($needle);

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

# Second most-voted answer
function endsWith3($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;
}

# Regex answer
function endsWith4($haystack, $needle) {
    return preg_match('/' . preg_quote($needle, '/') . '$/', $haystack);
}

function timedebug() {
    $test = 10000000;

    $time1 = microtime(true);
    for ($i=0; $i < $test; $i++) {
        $tmp = endsWith('TestShortcode', 'Shortcode');
    }
    $time2 = microtime(true);
    $result1 = $time2 - $time1;

    for ($i=0; $i < $test; $i++) {
        $tmp = endsWith2('TestShortcode', 'Shortcode');
    }
    $time3 = microtime(true);
    $result2 = $time3 - $time2;

    for ($i=0; $i < $test; $i++) {
        $tmp = endsWith3('TestShortcode', 'Shortcode');
    }
    $time4 = microtime(true);
    $result3 = $time4 - $time3;

    for ($i=0; $i < $test; $i++) {
        $tmp = endsWith4('TestShortcode', 'Shortcode');
    }
    $time5 = microtime(true);
    $result4 = $time5 - $time4;

    echo $test.'x endsWith: '.$result1.' seconds # This answer<br>';
    echo $test.'x endsWith2: '.$result4.' seconds # Accepted answer<br>';
    echo $test.'x endsWith3: '.$result2.' seconds # Second most voted answer<br>';
    echo $test.'x endsWith4: '.$result3.' seconds # Regex answer<br>';
    exit;
}
timedebug();

ベンチマーク結果:

10000000x endsWith: 1.5760900974274 seconds # This answer
10000000x endsWith2: 3.7102129459381 seconds # Accepted answer
10000000x endsWith3: 1.8731069564819 seconds # Second most voted answer
10000000x endsWith4: 2.1521229743958 seconds # Regex answer

3
時間をかけてさまざまなソリューションを比較し、実際にそれらをベンチマークするための+1!言語が進化するにつれて最適化が行われるため、使用したPHPのバージョンについても言及する必要があります。PHPのバージョン間での文字列比較関数の劇的な改善を見てきました:)
Christophe Deliens

1
@ChristopheDeliensと、PHPバージョンを提供するという彼のリクエストを反映しています。私は7.3.2でテストを実行し、FWIWで同様の結果を得ました。
ジェフ

16

これは完了したと思いますが、比較する文字列の長さを入力できるので、strncmpを確認することをお勧めします。

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

これでどうやって終わりますか?
mpen 2011

@Mark-受け入れられた答えを見ることができますが、主にそれがより安全だと思うので、私はstrncmpを使用することを好みます。
ジェームズブラック

具体的にはstrncmpを意味します。オフセットは指定できません。つまり、endsWith関数は別のメソッドを完全に使用する必要があります。
mpen 2011

@Mark -endsWithの場合、strrpos(php.net/manual/en/function.strrpos.php)を使用するだけですが、一般的に、strcmpを使用するときはいつでもstrncmpがおそらくより安全なオプションです。
ジェームズブラック

11

あなたが使用することができますstrposし、strrpos

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

1
strpos($sHaystack, $sNeedle) == 0このようにここでトリプルイコールを使用する必要がありますstrpos($sHaystack, $sNeedle) === 0か?にfalse == 0評価すると、バグが表示されtrueます。
Kalyan 2017年

11

受け入れられた回答のマルチバイトセーフバージョンを以下に示します。UTF-8文字列に対しては正常に機能します。

function startsWith($haystack, $needle)
{
    $length = mb_strlen($needle, 'UTF-8');
    return (mb_substr($haystack, 0, $length, 'UTF-8') === $needle);
}

function endsWith($haystack, $needle)
{
    $length = mb_strlen($needle, 'UTF-8');
    return $length === 0 ||
        (mb_substr($haystack, -$length, $length, 'UTF-8') === $needle);
}

2
これはCPUの無駄遣いに過ぎません。StarstWithとEndsWithの場合、確認する必要があるのは、バイトが一致することを確認することだけです。これが、受け入れられた回答が正確に行っていることです。この1は、針のutf8文字の数、および干し草のn番目のutf8文字の位置の計算に時間を浪費します。100%確実ではないので、これはCPUの無駄です。受け入れられた答えが失敗する実際のテストケースを思い付くことができますが、これは失敗しませんか?
hanshenrik

2
@hanshenrik-非常にまれなケースですが、UTF8と同じバイトを含み、最後の文字の半分が欠落している文字列を探す場合に発生する可能性があります。同様に、Unicode C5 91(文字 "ő")があり、C5(文字 "Å")を探しても、一致するはずはありません。その一方で、確かに、なぜutf haystackで非utfの針を検索するのでしょう...しかし、防弾チェックの場合、これは可能性と考えなければなりません。
dkellner 2018

startsWith、それがあるべき$length = mb_strlen($needle, 'UTF-8');
トーマスKekeisen

2
@ThomasKekeisenありがとう、修正しました。
Vahid Amiri

8

正規表現のない短くてわかりやすいワンライナー。

startsWith()は簡単です。

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

endWith()は、少し派手で遅いstrrev()を使用しています。

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

@FrancescoMM:strposは「適切なツール」ではありません ...なぜですか?では、「適切なツール」とは何でしょうか。 編集:私はあなたの答えを以下に読みます。プログラミングは、あなたが持っているリソースを使用する発明のようなものだと思いました。だから、正しいことも悪いこともありません...機能するかしないかだけです...パフォーマンスは副次的です。
Fr0zenFyr 2018年

「それは比較のためではなく、検索のためのツールだから?」Cit。アリストテレス
FrancescoMM

7

文字列が空でないことが確実な場合は、startswithに焦点を合わせ、比較やstrlenなどの前に最初の文字にテストを追加すると、処理が少し速くなります。

function startswith5b($haystack, $needle) {
    return ($haystack{0}==$needle{0})?strncmp($haystack, $needle, strlen($needle)) === 0:FALSE;
}

なんとか(20%〜30%)高速です。$ haystack {1} === $ needle {1}のような別のcharテストを追加しても、速度はそれほど向上しないようで、遅くなることさえあります。

===より速いと思われる== 条件演算子は(a)?b:c速くよりも思えますif(a) b; else c;


「なぜstrposを使わないのですか?」他のソリューションを「不必要な作業」と呼ぶ


strposは高速ですが、このジョブに適したツールではありません。

理解するために、ここに例としての小さなシミュレーションがあります:

Search a12345678c inside bcdefga12345678xbbbbb.....bbbbba12345678c

コンピュータは「内部」で何をしますか?

    With strccmp, etc...

    is a===b? NO
    return false



    With strpos

    is a===b? NO -- iterating in haysack
    is a===c? NO
    is a===d? NO
    ....
    is a===g? NO
    is a===g? NO
    is a===a? YES
    is 1===1? YES -- iterating in needle
    is 2===3? YES
    is 4===4? YES
    ....
    is 8===8? YES
    is c===x? NO: oh God,
    is a===1? NO -- iterating in haysack again
    is a===2? NO
    is a===3? NO
    is a===4? NO
    ....
    is a===x? NO
    is a===b? NO
    is a===b? NO
    is a===b? NO
    is a===b? NO
    is a===b? NO
    is a===b? NO
    is a===b? NO
    ...
    ... may many times...
    ...
    is a===b? NO
    is a===a? YES -- iterating in needle again
    is 1===1? YES
    is 2===3? YES
    is 4===4? YES
    is 8===8? YES
    is c===c? YES YES YES I have found the same string! yay!
    was it at position 0? NOPE
    What you mean NO? So the string I found is useless? YEs.
    Damn.
    return false

strlenが文字列全体を反復しないと仮定すると(その場合でも)、これはまったく便利ではありません。


最初の文字が異なる場合にのみ、速度が向上します。
ジャック

2
@ジャックはい、もちろん、アイデアは統計的に発生するということです。したがって、スピードアップは一般に、テストセット全体(それが変わらない場合を含む)全体で20%〜30%です。それらが異なる場合、あなたは多くを獲得し、そうでない場合、ほとんど失うことはありません。平均で30%向上します(セットによって異なりますが、大規模なテストでは速度が向上します)
FrancescoMM

「しかし、それはこの仕事にふさわしい道具ではない」 ...引用はある?
Fr0zenFyr 2018年

1
WTF。誰を引用するべきか、以下にすべてのプロセスをリストしましたか?文字列の最後まで検索する関数を使用して、最初の文字が「a」ではないことを通知しますか?誰が気にする?比較のためではなく、検索のためのツールであるため、適切なツールではありません。アリストテレスを引用して明白に述べる必要はありません。
FrancescoMM

6

以下の答えが効率的で簡単かもしれないことを願っています:

$content = "The main string to search";
$search = "T";
//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';

6

私は通常、最近はunderscore-phpのようなライブラリーを使用することになります。

require_once("vendor/autoload.php"); //use if needed
use Underscore\Types\String; 

$str = "there is a string";
echo( String::startsWith($str, 'the') ); // 1
echo( String::endsWith($str, 'ring')); // 1   

ライブラリには他の便利な関数がたくさんあります。


6

その答えによってMPENは、残念ながら、提供ベンチマークは非常に重要かつ有害な監督を持って、信じられないほど徹底しているが、。

needlesとhaystackのすべてのバイトは完全にランダムであるため、needle-haystackペアが最初のバイトで異なる確率は99.609375%です。これは、平均して、100000バイトのペアの約99609が最初のバイトで異なることを意味します。 。つまり、ベンチマークはstartswith、最初のバイトを明示的にチェックする実装に大きく偏ってstrncmp_startswith2います。

代わりに、テスト生成ループが次のように実装されている場合:

echo 'generating tests';
for($i = 0; $i < 100000; ++$i) {
    if($i % 2500 === 0) echo '.';

    $haystack_length = random_int(1, 7000);
    $haystack = random_bytes($haystack_length);

    $needle_length = random_int(1, 3000);
    $overlap_length = min(random_int(0, $needle_length), $haystack_length);
    $needle = ($needle_length > $overlap_length) ?
        substr($haystack, 0, $overlap_length) . random_bytes($needle_length - $overlap_length) :
        substr($haystack, 0, $needle_length);

    $test_cases[] = [$haystack, $needle];
}
echo " done!<br />";

ベンチマークの結果は、少し異なるストーリーを示しています。

strncmp_startswith: 223.0 ms
substr_startswith: 228.0 ms
substr_compare_startswith: 238.0 ms
strncmp_startswith2: 253.0 ms
strpos_startswith: 349.0 ms
preg_match_startswith: 20,828.7 ms

もちろん、このベンチマークはまだ完全に公平ではないかもしれませんが、部分的に一致する針が与えられたときのアルゴリズムの効率もテストします。


5

要するに:

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

function endsWith($str, $needle){
   $length = strlen($needle);
   return !$length || substr($str, - $length) === $needle;
}

5

ただの推奨事項:

function startsWith($haystack,$needle) {
    if($needle==="") return true;
    if($haystack[0]<>$needle[0]) return false; // ------------------------- speed boost!
    return (0===substr_compare($haystack,$needle,0,strlen($needle)));
}

文字列の最初の文字を比較するその余分な行により、誤った大文字と小文字がすぐに返される可能性があります。そのため、多くの比較がはるかに速くなります(私が測定した場合は7倍速く)。実際のケースでは、その1行のパフォーマンスに実質的に料金を払わないので、含める価値があると思います。(また、実際には、特定の開始チャンクについて多くの文字列をテストする場合、一般的なケースでは何かを探しているため、ほとんどの比較は失敗します。)


2
コードのバグ: startsWith("123", "0")与えtrue
ティノ

うん、悪い!$チェックが起こった。ごめんなさい!(3行目の概念を説明したかっただけです)
dkellner

4

このsubstr関数はfalse多くの特殊なケースで戻る可能性があるため、これらの問題を処理する私のバージョンを次に示します。

function startsWith( $haystack, $needle ){
  return $needle === ''.substr( $haystack, 0, strlen( $needle )); // substr's false => empty string
}

function endsWith( $haystack, $needle ){
  $len = strlen( $needle );
  return $needle === ''.substr( $haystack, -$len, $len ); // ! len=0
}

テスト(true良い意味):

var_dump( startsWith('',''));
var_dump( startsWith('1',''));
var_dump(!startsWith('','1'));
var_dump( startsWith('1','1'));
var_dump( startsWith('1234','12'));
var_dump(!startsWith('1234','34'));
var_dump(!startsWith('12','1234'));
var_dump(!startsWith('34','1234'));
var_dump('---');
var_dump( endsWith('',''));
var_dump( endsWith('1',''));
var_dump(!endsWith('','1'));
var_dump( endsWith('1','1'));
var_dump(!endsWith('1234','12'));
var_dump( endsWith('1234','34'));
var_dump(!endsWith('12','1234'));
var_dump(!endsWith('34','1234'));

また、substr_compare機能も一見の価値があります。 http://www.php.net/manual/en/function.substr-compare.php



4

私はこのようにします

     function startWith($haystack,$needle){
              if(substr($haystack,0, strlen($needle))===$needle)
              return true;
        }

  function endWith($haystack,$needle){
              if(substr($haystack, -strlen($needle))===$needle)
              return true;
        }

一致しない場合はfalseを返すのを忘れます。関数の戻り値は「想定」されるべきではないので、誤りは正しくありませんが、少なくとも他の回答と比較して、あなたが何をしているのかはわかっています。
2016年

3

James Blackの回答に基づいて、endsWithバージョンは次のとおりです。

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

function endsWith($haystack, $needle, $case=true) {
     return startsWith(strrev($haystack),strrev($needle),$case);

}

注:strncasecmpは実際にはstrncmpの大文字と小文字を区別しないバージョンであるため、James BlackのstartsWith関数のif-else部分を交換しました。


2
strrev()創造的ですが、特に非常にコストがかかることに注意してください。
Alexis Wilke 2014年

===代わりに==を使用してください。0PHPの多くのことと同じです。
nawfal

3

以下はなぜですか?

//How to check if a string begins with another string
$haystack = "valuehaystack";
$needle = "value";
if (strpos($haystack, $needle) === 0){
    echo "Found " . $needle . " at the beginning of " . $haystack . "!";
}

出力:

valuehaystackの最初に値が見つかりました!

覚えておいて、strpos針が干し草の山で見つからなかった場合はfalseを返し、針がインデックス0(AKA初め)で発見された、とだけ、場合場合は0を返します。

そしてこれがendsWithです:

$haystack = "valuehaystack";
$needle = "haystack";

//If index of the needle plus the length of the needle is the same length as the entire haystack.
if (strpos($haystack, $needle) + strlen($needle) === strlen($haystack)){
    echo "Found " . $needle . " at the end of " . $haystack . "!";
}

このシナリオでは、関数startsWith()は必要ありません。

(strpos($stringToSearch, $doesItStartWithThis) === 0)

trueまたはfalseを正確に返します。

ここでは、すべての野生の関数が蔓延しているので、これは単純です。


3
"x"を "a"と比較してFALSEを返すのではなく、文字列 "abcdefghijklmxyz"内で "xy"を検索している場合、 "a"から "m"までのすべての文字を検索し、最終的に "xy"を見つけることになります。文字列の中で、その位置がゼロではないため、最後にFALSEを返します!これはあなたがしていることであり、ここで他の蔓延している機能より奇妙でワイルドです。
FrancescoMM

単純化は論理ではなく型付けにあります。
Kade Hafen

それは論理ではなく、フランスコが指摘していた可能性のある最適化です。strpos()一致する場合を除いて、使用は遅くなります。strncmp()この場合ははるかに良いでしょう。
Alexis Wilke 14

このような低レベルの機能を実行しているときは、何百万回も呼び出されるため、通常は、どんなに複雑であっても、最も速度が最適化されたソリューションを求めます。ここで増減するマイクロ秒ごとに、非常に現実的な違いが生じます。見た目をよくし、何が悪いのかさえわからないときに恐ろしい時間を失うのではなく、地獄をうまく調整して(そして、複雑さを忘れてください)一致しない2GB文字列をチェックすることを想像してみてください。
dkellner 2018

3

以前の回答の多くも同様に機能します。しかし、これはあなたがそれを作って、あなたが望むことをさせることができる限り短いかもしれません。あなたはそれが「真に戻る」ことを望んでいると述べるだけです。そのため、ブール値のtrue / falseとテキストのtrue / falseを返すソリューションを含めました。

// boolean true/false
function startsWith($haystack, $needle)
{
    return strpos($haystack, $needle) === 0 ? 1 : 0;
}

function endsWith($haystack, $needle)
{
    return stripos($haystack, $needle) === 0 ? 1 : 0;
}


// textual true/false
function startsWith($haystack, $needle)
{
    return strpos($haystack, $needle) === 0 ? 'true' : 'false';
}

function endsWith($haystack, $needle)
{
    return stripos($haystack, $needle) === 0 ? 'true' : 'false';
}

本当です。しかし、ピーターは文字列で機能する関数を求めていました。それにもかかわらず、私はあなたをなだめるために私の答えを更新しました。
wynshaft 2014年

編集後、ソリューションは完全に廃止されました。これは'true''false'文字列として返されますtrue。どちらもブール値の意味です。それはunderhanded.xcott.comのようなものには良いパターンです;)
Tino

まあ、ピーターは彼がそれを「本当」に戻すことを望んだと述べました。それで、私は彼が求めたものを返すと思った。彼が望んでいなかった場合に備えて、両方のバージョンを追加しました。
wynshaft 2014年

2

正規表現を使用することもできます。

function endsWith($haystack, $needle, $case=true) {
  return preg_match("/.*{$needle}$/" . (($case) ? "" : "i"), $haystack);
}

3
$ needleはでエスケープする必要がありpreg_quote($needle, '/')ます。
Timo Tijhof

2

コピーなし、インターンループなし:

function startsWith(string $string, string $start): bool
{
    return strrpos($string, $start, - strlen($string)) !== false;
}

function endsWith(string $string, string $end): bool
{
    return ($offset = strlen($string) - strlen($end)) >= 0 
    && strpos($string, $end, $offset) !== false;
}

これはMrHusの実装よりもはるかに高速です。ベンチマークするかもしれません
hanshenrik

1

PHP 4の効率的なソリューションを次に示します。のsubstr_compare代わりにを使用することにより、PHP 5でより高速な結果を得ることができますstrcasecmp(substr(...))

function stringBeginsWith($haystack, $beginning, $caseInsensitivity = false)
{
    if ($caseInsensitivity)
        return strncasecmp($haystack, $beginning, strlen($beginning)) === 0;
    else
        return strncmp($haystack, $beginning, strlen($beginning)) === 0;
}

function stringEndsWith($haystack, $ending, $caseInsensitivity = false)
{
    if ($caseInsensitivity)
        return strcasecmp(substr($haystack, strlen($haystack) - strlen($ending)), $haystack) === 0;
    else
        return strpos($haystack, $ending, strlen($haystack) - strlen($ending)) !== false;
}

0

これにはfnmatch関数を使用できます。

// Starts with.
fnmatch('prefix*', $haystack);
// Ends with.
fnmatch('*suffix', $haystack);

警告、バイナリセーフではなく、ワイルドカードを含む針に対しても安全ではない= /
hanshenrik
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.