web-dev-qa-db-ja.com

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

指定された文字/文字列で始まる場合と文字列で終わる場合に返される2つの関数を書く方法を教えてください。

例えば:

$str = '|apples}';

echo startsWith($str, '|'); //Returns true
echo endsWith($str, '}'); //Returns true
1336
Click Upvote
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);
}

正規表現を使いたくない場合はこれを使用してください。

1436
MrHus

substr_compare 関数を使用してstart-withとends-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の干し草の山、さまざまな長さの針、完全、部分、および不一致の各ケースに対してテスト済み。 strncmpはstarts-withの方が速いですが、ends-withをチェックすることはできません。

959
Salman A

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

231
mpen
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);
}

貸方

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

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

46
KdgDev

正規表現は上記のように機能しますが、他にも微調整を加えた上で提案されています。

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

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

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

文字列が '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()など)を定義する必要はありません。

しかし、繰り返しますが、これはすべてのケースの解決策ではなく、この非常に具体的なケースだけです。

23
noamtm

スピードがあなたにとって重要であるならば、これを試してください(私はそれが最速の方法だと思います)

文字列と$ 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
22
lepe

一時的な文字列を導入しない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;
}
17
Ja͢ck

私はこれが終了したことを実感しますが、比較するために文字列の長さを入れることができるので strncmp を見ることをお勧めします。

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

最も速い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
12

strpos および strrpos を使用できます。

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

正規表現なしで短くて理解しやすいワンライナー。

startsWith()は簡単です。

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

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

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

これは受け入れられた答えのマルチバイトセーフバージョンです、それは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);
}
8
Vahid Amiri

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

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

それはどういうわけか(20%-30%)速いです。 $ haystack {1} === $ needle {1}のような文字テストをもう1つ追加しても、速度が上がるとは思われませんが、遅くなることさえあります。

=====より速いようです。条件演算子(a)?b:cif(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が文字列全体を反復しないと仮定すると(しかしその場合でも)、これはまったく便利ではありません。

7
FrancescoMM

私はたいてい 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
yuvilio

answer by mpen は信じられないほど徹底的ですが、残念ながら、提供されたベンチマークは非常に重要で有害な監視をしています。

針と干し草の山のすべてのバイトは完全にランダムなので、針と干し草の山のペアが一番最初のバイトで異なる確率は99.609375%です。 。言い換えれば、ベンチマークはstrncmp_startswith2が行うように、最初のバイトを明示的にチェックするstartswithの実装に大きく偏っています。

テスト生成ループが代わりに次のように実装されているとします。

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

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

6
Veeno

私は以下の答えが効率的でそしてまた簡単であるかもしれないと思います:

$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
Srinivasan.S

ただのお勧め:

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

この余分な行は、文字列の最初の文字を比較すると、 すぐに という誤った大文字と小文字の区別が返される可能性があります。本当の場合、あなたはその単一のラインのためにパフォーマンスに実質的に代償を払わないので、私はそれが含める価値があると思います。 (また、実際には、特定の開始チャンクに対して多数の文字列をテストするとき、通常は何かを探しているため、ほとんどの比較は失敗します。)

4
dkellner

どうして次のことじゃないの?

//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を返します。

そしてこれが終わりです。

$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を正確に返します。

奇妙に思われるかもしれませんが、すべてのワイルド関数がここではびこっています。

4
Kade Hafen

これはうまくいくかもしれません

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

ソース: https://stackoverflow.com/a/4419658

4
user507410

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
biziclop

要するに:

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

function endsWith($str, $needle){
   $length = strlen($needle);
   return !$length || substr($str, - $length) === $needle;
}
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;
        }
4
Jelle Keizer

正規表現も使えます。

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

以前の回答の多くも同様に機能します。しかしながら、これはあなたがそれを作り、あなたが望むものをそれにさせることができるのと同じくらい短いかもしれません。あなたはそれを 'trueを返す'ことを望んでいると言っているだけです。そのため、ブール値の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';
}
3
wynshaft

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
bobo

これはPHP 4の効率的な解決策です。PHP 5では、strcasecmp(substr(...))の代わりにsubstr_compareを使用すると、より速い結果が得られます。

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;
}
1
Patrick Smith

コピー禁止およびインターンループ禁止:

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

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