php - preg_match - strrpos
PHPのstartsWith()関数とendsWith()関数 (20)
最も速い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
どのように文字列を取り、指定された文字/文字列で始まるか、それで終わるかを返す2つの関数を書くことができますか?
例えば:
$str = '|apples}';
echo startsWith($str, '|'); //Returns true
echo endsWith($str, '}'); //Returns true
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
strrpos
とstrpos
をstrpos
てstart-withとends-withをそれぞれチェックすることができます。
strrpos
を使ってstrrpos
withとstrpos
をチェックして終了をチェックすると、最後まで文字列全体をチェックするのではなく、できるだけ早く戻ります。 また、このソリューションは一時的な文字列を作成しません。 downvotingする前の理由を説明することを検討してください。 ちょうどDWTFのfwitがこの関数の仕組みを理解していないか、1つの解決策しかないと考えていても、この答えが間違っているわけではありません。
function startsWith($haystack, $needle) {
// search backwards starting from haystack length characters from the end
return $needle === ''
|| strrpos($haystack, $needle, -strlen($haystack)) !== false;
}
function endsWith($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;
}
テストと結果( これと比較 ):
startsWith('abcdef', 'ab') -> true
startsWith('abcdef', 'cd') -> false
startsWith('abcdef', 'ef') -> false
startsWith('abcdef', '') -> true
startsWith('', 'abcdef') -> false
endsWith('abcdef', 'ab') -> false
endsWith('abcdef', 'cd') -> false
endsWith('abcdef', 'ef') -> true
endsWith('abcdef', '') -> true
endsWith('', 'abcdef') -> false
注: strncmp
およびsubstr_compare
関数はこの関数より優れています。
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
ここでは、受け入れられた回答のマルチバイトの安全なバージョンですが、UTF-8文字列でうまく動作します。
function startsWith($haystack, $needle)
{
$length = mb_substr($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);
}
これは動作するかもしれません
function startsWith($haystack, $needle) {
return substr($haystack, 0, strlen($needle)) == $needle;
}
出典: https://.com/a/4419658 : https://.com/a/4419658
ちょうど推薦:
function startsWith($haystack,$needle) {
if($needle==="") return true;
if($haystack[0]<>$needle[0]) return false;
if(substr_compare($haystack,$needle,0,strlen($needle))==0) return true;
return false;
}
その余分な行は、文字列の最初の文字を比較すると、即時に偽のケースを返すことができるので、多くの比較がずっと速くなります(測定したときには7倍速くなります)。真のケースでは、その1行のパフォーマンスで実質的に価格を支払わないので、それを含める価値はあると思います。(実際には、特定の開始チャンクに対して多くの文字列をテストする場合、典型的なケースでは何かを探しているので、ほとんどの比較は失敗します)。
のanswerは信じられないほど徹底的ですが、残念ながら、提供されたベンチマークは非常に重要で有害な監視をしています。
針と干し草の中のすべてのバイトは完全にランダムなので、最初の1バイトで針の干し草の組が異なる確率は99.609375%であり、これは平均して100000組のうち約99609が最初のバイト。 言い換えると、ベンチマークはstartswith
のように最初のバイトを明示的にチェックする実装の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
もちろん、このベンチマークは依然として完全に偏っているわけではありませんが、部分的に一致する針があればアルゴリズムの効率もテストされます。
また、正規表現を使用することもできます。
function endsWith($haystack, $needle, $case=true) {
return preg_match("/.*{$needle}$/" . (($case) ? "" : "i"), $haystack);
}
一時的な文字列を導入しない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;
}
今までのすべての答えは、不要な作業、 strlen calculations
、 string allocations (substr)
などの負荷をかけているようです。 'strpos'
と'stripos'
関数は$needle
'stripos'
$needle
最初の出現のインデックスを返します:
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($needle, $haystack) {
return preg_match('/^' . preg_quote($needle, '/') . '/', $haystack);
}
function endsWith($needle, $haystack) {
return preg_match('/' . preg_quote($needle, '/') . '$/', $haystack);
}
短く理解しやすい正規表現のないライナー。
startsWith()は簡単です。
function startsWith($haystack, $needle) {
return (strpos($haystack, $needle) === 0);
}
endsWith()は、やや上手くゆっくりしたstrrev()を使います:
function endsWith($haystack, $needle) {
return (strpos(strrev($haystack), strrev($needle)) === 0);
}
私はこれを好きになるだろう
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;
}
私は最近、 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
ライブラリは他の便利な機能でいっぱいです。
ここでは、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;
}
これまでの回答の多くはまったく同じように機能します。しかし、これはおそらくあなたが作ったものと同じくらい短く、あなたが望むものをやり遂げることができます。あなたはそれが「真実に戻ってほしい」と述べているだけです。だから私はブール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';
}
$ends_with = strrchr($text, '.'); // Ends with dot
$start_with = (0 === strpos($text, '.')); // Starts with dot
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);
}
正規表現を使用したくない場合は、これを使用します。