itsource

PHP의 startsWith() 및 endsWith() 함수

mycopycode 2023. 1. 8. 14:39
반응형

PHP의 startsWith() 및 endsWith() 함수

지정된 문자/문자열로 시작하거나 문자열로 끝나는 경우 문자열을 사용하여 반환되는 두 가지 함수를 작성하려면 어떻게 해야 합니까?

예를 들어 다음과 같습니다.

$str = '|apples}';

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

PHP 8.0 이후

PHP 8.0을 사용할 수 있습니다.

str_starts_with 수동

str_ends_with 설명서

echo str_starts_with($str, '|');

PHP 8.0 이전 버전

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

함수를 사용하여 시작과 끝을 확인할 수 있습니다.

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(벤치마크 스크립트)에서 가장 빠른 솔루션 중 하나입니다.8KB 건초 더미, 다양한 길이의 바늘 및 완전, 부분 및 미매치 케이스에 대해 테스트. strncmp시작은 빠르지만 끝을 확인할 수는 없습니다.

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

starts with_displays.php

은 모두 한 작업을 하고 것 같습니다.strlen calculations,string 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;
}
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);
}

크레디트 대상:

문자열이 다른 문자열로 끝나는지 확인합니다.

문자열이 다른 문자열로 시작되는지 확인합니다.

PHP 8 업데이트

PHP 8에는 이 문제에 대한 성능과 편리한 솔루션을 제공하는 새로운 기능과 기능이 포함되어 있습니다.

$str = "beginningMiddleEnd";
if (str_starts_with($str, "beg")) echo "printed\n";
if (str_starts_with($str, "Beg")) echo "not printed\n";
if (str_ends_with($str, "End")) echo "printed\n";
if (str_ends_with($str, "end")) echo "not printed\n";

이 기능의 RFC에서는, 상세한 것에 대해 설명하고 있습니다.또, 명백한(명확하지 않은) 유저 랜드의 실장의 장점과 문제에 대해서도 설명합니다.

이 질문에는 이미 많은 답변이 있지만, 경우에 따라서는 모든 답변보다 간단한 것으로 만족할 수 있습니다.원하는 문자열이 알려진 경우(하드코드) 따옴표 없이 정규 표현을 사용할 수 있습니다.

문자열이 '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()해 주세요를 참조해 주세요.

하지만 다시 말씀드리지만, 이것은 모든 경우에 대한 해결책은 아닙니다. 단지 이 매우 구체적인 해결책일 뿐입니다.

regex는 위에서 기능하지만 위에서 제시한 다른 수정사항도 있습니다.

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

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

Fastest Ends With() 솔루션:

# 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

만약 속도가 중요하다면, 이것을 시도해 보세요.(가장 빠른 방법이라고 생각합니다)

$haystack이 1글자일 경우에만 사용할 수 있습니다.

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

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

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

다음은 임시 문자열을 도입하지 않는 두 가지 기능으로, 바늘이 상당히 클 때 유용할 수 있습니다.

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

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

이것이 끝난 것은 알고 있습니다만, strncmp 를 참조해 주세요.이것에 의해, 비교할 문자열의 길이를 지정할 수 있기 때문에, 다음과 같이 됩니다.

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

다음은 수신된 답변의 안전한 멀티바이트 버전입니다. 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);
}

및 을 사용할 수 있습니다.

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

규칙적인 표현이 없는 짧고 알기 쉬운 한 줄.

startsWith()는 스트레이트입니다.

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

endsWith()는 약간 화려하고 느린 strrev()를 사용합니다.

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

starts with에 초점을 맞추면 문자열이 비어 있지 않은 경우 비교 전 첫 번째 글자에 테스트를 추가하면 작업 속도가 약간 빨라집니다.

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

어떻게든(20~30%) 빠르다.$secstack{1}===$sec{1}과 같은 다른 문자 테스트를 추가하면 속도가 크게 향상되지 않을 수 있습니다.

=== 빠른 것 같다== 연산자 " " " "(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이 문자열 전체를 반복하지 않는다고 가정하면(그 경우에도), 이것은 전혀 편리하지 않습니다.

다음 답변이 효율적이고 간단하기를 바랍니다.

$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';

요즘은 언더스코어 같은 도서관으로 가게 됩니다.

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   

도서관은 다른 편리한 기능들로 가득 차 있다.

mpen답변은 믿을 수 없을 정도로 철저하지만 불행히도 제공된 벤치마크는 매우 중요하고 해로운 감시를 가지고 있다.

니들 및 건초더미 내의 모든 바이트는 완전히 랜덤이기 때문에 니들-헤이스택 쌍이 첫 번째 바이트에서 다를 확률은 99.609375%입니다. 즉, 평균적으로 100,000 쌍 중 99609개가 첫 번째 바이트에서 다릅니다.는 ,, 치, 이, 이, 이, 이, in, in, in, in, in, in, in, in에 크게 치우쳐 있습니다.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

물론 이 벤치마크는 여전히 완전히 편견이 없는 것은 아니지만 부분적으로 일치하는 바늘이 주어졌을 때 알고리즘의 효율성도 테스트한다.

요컨대:

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

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

고속화:

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배 빠릅니다).실제로 그 단일 라인의 퍼포먼스에는 거의 비용을 들이지 않기 때문에 포함할 가치가 있다고 생각합니다.(또한 실제로 특정 시작 청크에 대해 다수의 스트링을 테스트하면 일반적인 경우 무언가를 찾고 있기 때문에 대부분의 비교는 실패합니다.)

메모: 아래 @Tino 코멘트의 버그는 수정되었습니다.

문자열 대 정수

문자열 비교를 강제하려면(즉, startsWith("1234", 12) true가 될 것으로 예상함) 다음과 같이 타이프캐스팅이 필요합니다.

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

필수는 아니지만 흥미로운 케이스이기 때문에 "boolean true는 t로 시작합니까?"와 같은 질문을 하게 됩니다.그래서 당신이 결정하지만 반드시 좋은 결정을 내려야 합니다.

이것은 효과가 있을 수 있습니다.

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

출처 : https://stackoverflow.com/a/4419658

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

왜 다음과 같이 하지 않는가?

//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를 정확하게 반환합니다.

여기 모든 야생 기능이 난무하는 게 이렇게 간단한 게 이상해보여.

저는 이렇게 하고 싶어요.

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

James Black의 답변에 따르면 버전 포함 종료는 다음과 같습니다.

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

}

주의: James Black의 시작과 if-else 부품을 교환했습니다.함수에서는 strncasecmp는 실제로는 대소문자를 구분하지 않는 strncmp 버전이기 때문입니다.

이전 답변의 상당수도 마찬가지로 유효합니다.하지만, 이것은 당신이 원하는 것을 할 수 있는 한 짧게 할 수 있습니다.'참'으로 되돌리고 싶다고만 하면 됩니다.따라서 부울 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';
}

복사 및 내부 루프 없음:

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

PHP4. PHP 4의 에서 PHP 5를 하면 더 수 .substr_comparestrcasecmp(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;
}

정규 표현도 사용할 수 있습니다.

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

언급URL : https://stackoverflow.com/questions/834303/startswith-and-endswith-functions-in-php

반응형