les fonctions startsWith() et endsWith () en PHP
Comment puis-je écrire deux fonctions qui prendraient une chaîne et reviendraient si elle commence avec le caractère/chaîne spécifié ou se termine avec elle?
par exemple:
$str = '|apples}';
echo startsWith($str, '|'); //Returns true
echo endsWith($str, '}'); //Returns true
30 réponses
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);
}
utilisez ceci si vous ne voulez pas utiliser un regex.
il est possible d'utiliser strrpos
et strpos
pour vérifier respectivement le début-avec et les fins-avec.
notez que l'utilisation de strrpos
pour vérifier commence par et strpos
pour vérifier se termine par retournera dès que possible au lieu de vérifier la chaîne entière jusqu'à la fin. De plus, Cette solution ne crée pas de chaîne temporaire. Pensez à expliquer la raison avant de réduire le vote. Juste parce qu'un F-wit au DWTF ne comprend pas comment cette fonction fonctionne ou pense qu'il n'y a qu'une seule solution ne signifie pas que cette réponse est fausse.
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;
}
essais et résultats ( comparer avec ce ):
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
Note: les fonctions strncmp
et substr_compare
seront plus performantes que cette fonction.
Mise À Jour Le 23-Août-2016
fonctions
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;
}
Essais
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";
}
Results (PHP 7.0.9)
(trié de la plus rapide à la plus lente)
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
Results (PHP 5.3.29)
(trié de la plus rapide à la plus lente)
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
Toutes les réponses jusqu'à présent ne semblent charge de travail inutile, strlen calculations
, string allocations (substr)
, etc. Les fonctions 'strpos'
et 'stripos'
renvoient l'index de la première occurrence de $needle
dans $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);
}
Crédit À :
Les fonctions regex ci-dessus, mais avec les autres tweaks également suggéré ci-dessus:
function startsWith($needle, $haystack) {
return preg_match('/^' . preg_quote($needle, '/') . '/', $haystack);
}
function endsWith($needle, $haystack) {
return preg_match('/' . preg_quote($needle, '/') . '$/', $haystack);
}
Si la vitesse est importante pour vous, essayez ceci.(Je crois que c'est la méthode la plus rapide)
ne Fonctionne que pour les chaînes et si $haystack est à seulement 1 caractère
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
je me rends compte que cela a été terminé, mais vous pouvez vouloir regarder strncmp comme il vous permet de mettre la longueur de la chaîne de comparer contre, donc:
function startsWith($haystack, $needle, $case=true) {
if ($case)
return strncasecmp($haystack, $needle, strlen($needle)) == 0;
else
return strncmp($haystack, $needle, strlen($needle)) == 0;
}
voici deux fonctions qui n'introduisent pas de chaîne temporaire, qui pourrait être utile lorsque les aiguilles sont substantiellement grandes:
function startsWith($haystack, $needle)
{
return strncmp($haystack, $needle, strlen($needle)) === 0;
}
function endsWith($haystack, $needle)
{
return $needle === '' || substr_compare($haystack, $needle, -strlen($needle)) === 0;
}
cette question a déjà beaucoup de réponses, mais dans certains cas, vous pouvez vous contenter de quelque chose de plus simple que tous. Si la chaîne que vous recherchez est connue (hardcoded), vous pouvez utiliser des expressions régulières sans citer etc.
vérifier si une chaîne de caractères commence par "ABC":
preg_match('/^ABC/', $myString); // "^" here means beginning of string
se termine par "ABC":
preg_match('/ABC$/', $myString); // "$" here means end of string
dans mon cas simple, je voulais vérifier si une chaîne se termine par une barre oblique:
preg_match('/\/$/', $myPath); // slash has to be quoted
L'avantage: comme il est très court et simple, vous n'avez pas à définir une fonction (comme endsWith()
) comme indiqué ci-dessus.
Mais à nouveau-ce n'est pas une solution pour tous les cas, cette très spécifique.
Court et facile à comprendre, one-liners sans expressions régulières.
startsWith () est droit devant.
function startsWith($haystack, $needle) {
return (strpos($haystack, $needle) === 0);
}
endsWith() utilise le peu de fantaisie et de ralentir strrev():
function endsWith($haystack, $needle) {
return (strpos(strrev($haystack), strrev($needle)) === 0);
}
en se concentrant sur startswith, si vous êtes sûr que les chaînes ne sont pas vides, en ajoutant un test sur le premier char, avant la comparaison, le strlen, etc. accélère un peu les choses:
function startswith5b($haystack, $needle) {
return ($haystack{0}==$needle{0})?strncmp($haystack, $needle, strlen($needle)) === 0:FALSE;
}
il est en quelque sorte (20% -30%) plus rapide. L'ajout d'un autre char test, comme $haystack{1}===$aiguille{1} ne semble pas accélérer les choses, peut même ralentir.
===
semble plus rapide que ==
Opérateur conditionnel (a)?b:c
semble plus rapide que if(a) b; else c;
pour ceux qui demandent " pourquoi ne pas utiliser strpos?"l'appel à d'autres solutions "travail inutile"
strpos est rapide, mais il n'est pas le bon outil pour ce travail.
pour comprendre, voici un petit exemple de simulation:
Search a12345678c inside bcdefga12345678xbbbbb.....bbbbba12345678c
Ce que l'ordinateur fait de "l'intérieur"?
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
en supposant que strlen n'itère pas la chaîne entière (mais même dans ce cas) ce n'est pas pratique du tout.
je finis habituellement avec une bibliothèque comme underscore-php ces jours-ci.
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
La bibliothèque est pleine d'autres fonctions pratiques.
Le réponse par mpen est incroyablement complet, mais, malheureusement, la condition de référence a un rôle très important et préjudiciable à la surveillance.
parce que chaque octet dans les aiguilles et les meules de foin est complètement aléatoire, la probabilité qu'une paire aiguille-meule de foin différera sur le tout premier octet est de 99,609375%, ce qui signifie que, en moyenne, environ 99609 des 100000 paires différeront sur le tout premier octet. Dans d'autres en d'autres termes, le benchmark est fortement biaisé vers les implémentations startswith
qui vérifient explicitement le premier octet, comme le fait strncmp_startswith2
.
si la boucle génératrice d'essai est mise en œuvre comme suit:
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 />";
les résultats de la référence en dire un peu différente de l'histoire:
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
bien sûr, cette référence peut-être pas encore parfaitement impartiale, mais il teste l'efficacité des algorithmes lorsqu'donné partiellement correspondance des aiguilles.
Voici une version multi-octets sûre de la réponse acceptée, elle fonctionne très bien pour les chaînes 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);
}
j'espère que la réponse peut être efficace et aussi simple:
$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';
la fonction substr
peut retourner false
dans de nombreux cas spéciaux, donc voici ma version, qui traite de ces questions:
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
}
Essais ( true
signifie bon):
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'));
aussi, la fonction substr_compare
mérite aussi d'être recherchée.
http://www.php.net/manual/en/function.substr-compare.php
en bref:
function startsWith($str, $needle){
return substr($str, 0, strlen($needle)) === $needle;
}
function endsWith($str, $needle){
$length = strlen($needle);
return !$length || substr($str, - $length) === $needle;
}
solution d'extrémité la plus rapide ():
# Checks if a string ends in a string
function endsWith($haystack, $needle) {
return substr($haystack,-strlen($needle))===$needle;
}
la Référence:
# 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();
Les Résultats D'Un Benchmark:
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
Cela peut fonctionner
function startsWith($haystack, $needle) {
return substr($haystack, 0, strlen($needle)) == $needle;
}
pourquoi pas le suivant?
//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 . "!";
}
sortie:
valeur trouvée au début de la chaîne de valeur!
Gardez à l'esprit, strpos
renvoie false si l'aiguille n'a pas été trouvé dans la botte de foin, et sera de retour 0 si, et seulement si, l'aiguille a été trouvé à l'indice 0 (AKA le début).
et voici la fin:
$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 . "!";
}
dans ce scénario il n'y a pas besoin d'une fonction startsWith() comme
(strpos($stringToSearch, $doesItStartWithThis) === 0)
retournera vrai ou faux avec précision.
il semble étrange que ce soit aussi simple avec toutes les fonctions wild en cours d'exécution rampant ici.
je voudrais faire comme ceci
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;
}
juste une recommandation:
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;
}
cette ligne supplémentaire, en comparant le premier caractère des cordes, peut faire fausse déclaration de cas immédiatement , faisant donc plusieurs de vos comparaisons beaucoup plus rapide (7x plus rapide lorsque j'ai mesuré). Dans le vrai cas, vous payez pratiquement aucun prix dans la performance pour cette ligne simple, donc je pense qu'il vaut la peine d'inclure. (Aussi, dans la pratique, quand vous testez de nombreuses chaînes pour un morceau de départ spécifique, la plupart les comparaisons échoueront car dans un cas typique vous cherchez quelque chose.)
basé sur la réponse de James Black, voici sa version 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);
}
Note: j'ai remplacé la partie if-else par la fonction startsWith de James Black, Car strncasecmp est en fait la version de strncmp qui n'est pas sensible à la casse.
vous pouvez également utiliser des expressions régulières:
function endsWith($haystack, $needle, $case=true) {
return preg_match("/.*{$needle}$/" . (($case) ? "" : "i"), $haystack);
}
bon nombre des réponses précédentes fonctionneront aussi bien. Cependant, c'est peut-être aussi court que vous pouvez faire et faire ce que vous désirez. Tu dis juste que tu aimerais que ça "redevienne vrai". J'ai donc inclus des solutions qui renvoient les booléens true/false et le texte 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';
}
Voici une solution efficace pour PHP 4. Vous pouvez obtenir des résultats plus rapides si vous utilisez PHP 5 en utilisant substr_compare
au lieu de 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;
}
$ends_with = strrchr($text, '.'); // Ends with dot
$start_with = (0 === strpos($text, '.')); // Starts with dot
je ne sais Pas pourquoi c'est si difficile pour les gens. Substr fait un excellent travail et est efficace car vous n'avez pas besoin de rechercher la chaîne entière si elle ne correspond pas.
de plus, étant donné que je ne vérifie pas les valeurs entières mais que je compare les chaînes, Je n'ai pas nécessairement à me soucier du cas strict===. Cependant, === est une bonne habitude à prendre.
function startsWith($haystack,$needle) {
substring($haystack,0,strlen($needle)) == $needle) { return true; }
return false;
}
function endsWith($haystack,$needle) {
if(substring($haystack,-strlen($needle)) == $needle) { return true; }
return false;
}
ou encore mieux optimisé.
function startsWith($haystack,$needle) {
return substring($haystack,0,strlen($needle)) == $needle);
}
function endsWith($haystack,$needle) {
return substring($haystack,-strlen($needle)) == $needle);
}