PHP 문자열이 다른 문자열로 끝나는 지 여부에 대한 가장 효율적인 테스트는 무엇입니까?


125

$str문자열 $test이 부분 문자열로 끝나는 지 여부를 테스트하는 표준 PHP 방법 은 다음 과 같습니다.

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

이것이 가장 빠른 방법입니까?



이 독립 실행 형 라이브러리 에서 찾을 수 s($str)->endsWith($test)있거나 s($str)->endsWithIgnoreCase($test)도움 이 될 수 있습니다 .
caw

답변:


152

Assaf의 말이 맞습니다. 이를 정확히 수행하기 위해 PHP에 내장 된 함수가 있습니다.

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

경우 $test더 이상보다 $str당신이 먼저 확인해야하므로, 경고를 줄 것이다 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;
}

좋은. Assaf가 지적했듯이 in-place 비교가 substr ()보다 빠를 것 같습니다.
Jason Cohen

2
mcrumley의 대답은 멋지지만 '=='대신 '==='를 사용해야합니다. '==='는 더 엄격하고 일반적으로 원하는 것을 수행하는 반면 '=='는 불쾌한 놀라움으로 이어질 수 있습니다. mcrumley의 세 번째 코드 스 니펫은 정확하지만 처음 두 개는 올바르지 않습니다. substr_compare ()는 일부 오류의 경우 false를 반환합니다. PHP에서는 false == 0이므로 코드 조각은 문자열이 발견되었음을 알립니다. ===를 사용하면 이런 일이 발생하지 않습니다.
jcsahnwaldt 모니카 복원

1
나는 오늘 PHP 5.5.11 이상에서 제공 한 솔루션을 깨뜨릴 버그를 만났습니다. bugs.php.net/bug.php?id=67043
user2180613 jul.

3 개의 함수 호출 오버 헤드가 가장 빠르지는 않습니다.
Thanh Trung

66

이 방법은 메모리가 조금 더 비싸지 만 더 빠릅니다.

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

바늘이 무엇인지 정확히 알고있는 경우에 가장 적합하므로 반대로 하드 코딩 할 수 있습니다. 프로그래밍 방식으로 바늘을 뒤집 으면 이전 방법보다 느려집니다.


2
-1 나는 이것이 더 빠르다는 것을 진지하게 의심하고 까다 롭습니다 (멋지지만 일반적으로 도움이되지는 않습니다). 건초 더미 바늘로 끝나지 않으면stripos 최악의 경우 전체 문자열을 반복하고 substr_compare최대 바늘 길이를 비교합니다. 예, substr_compare건초 더미 (그리고 훨씬 더 작은 바늘)의 길이를 계산해야하지만이 방법은이를 필요로 하고 전체를 복사하고 전체를 소문자로 변환하여 부팅 할 수 있습니다.
David Harkness

멋진 접근 방식이지만 많은 경우 비효율적입니다 (답변 자체에서 언급했듯이)! 여전히 이상하게 창의적이며 상상할 수있는 동일한 작업을 수행하는 더 많은 방법이 항상있을 수 있음을 보여준 것에 대한 찬성입니다. 건배!
Fr0zenFyr

1
나는이 방법을 테스트 한 결과 받아 들인 대답보다 빠릅니다. 건초 더미와 바늘을 모두 즉석에서 뒤집어도 더 빠릅니다.
Shumoapp

@DavidHarkness 의심이 정당한지 확인하기 위해 테스트 했습니까?
Nathan

@Nathan 아니요, substr_compare()잘 작동 하므로 벤치마킹 할 시간이 없습니다 .
David Harkness

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

음수 오프셋 "문자열 끝부터 계산 시작".


3
IMO는 제공된 솔루션에서 최고 중 하나
로마 Podlinov

내가 할 수 있다면 +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) 위치에서 char-by-char 루프를 수행하고 비교하는 것입니다. 그것은 당신이 할 수있는 최소한의 비교이며 여분의 메모리는 거의 사용되지 않습니다.



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

이것은 strlen을 제외하고 외부 함수를 호출하지 않는 순수한 PHP 입니다.

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

단일 문자 바늘의 경우 :

if (@strrev($haystack)[0] == $needle) {
   // yes, it ends...
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.