startsWith () et endsWith () fonctions en PHP
Question
Comment puis-je écrire deux fonctions qui prendraient une chaîne et renverraient si elle commence par le caractère / chaîne spécifié ou se termine par elle?
Par exemple:
$str = '|apples}';
echo startsWith($str, '|'); //Returns true
echo endsWith($str, '}'); //Returns true
La solution
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 de regex.
Autres conseils
Vous pouvez utiliser substr_compare
fonction pour vérifier début-avec et fin-avec:
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;
}
Cette solution devrait être l’une des solutions les plus rapides sur PHP 7 ( script de référence ). . Testé contre des meules de foin de 8 Ko, des aiguilles de différentes longueurs et des plaquettes complètes, partielles et sans correspondance. strncmp
est une touche plus rapide pour commencer-avec mais il ne peut pas vérifier les fins-avec.
Mis à 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;
}
Tests
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";
}
Résultats (PHP 7.0.9)
(Tri le plus rapide au plus lent)
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
Résultats (PHP 5.3.29)
(Tri le plus rapide au plus lent)
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 semblent faire beaucoup de travail inutile, calculs de strlen
, affectations de chaînes (substr)
, etc. Le '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éditer :
Les fonctions regex ci-dessus, mais avec les autres réglages également suggérés ci-dessus:
function startsWith($needle, $haystack) {
return preg_match('/^' . preg_quote($needle, '/') . '/', $haystack);
}
function endsWith($needle, $haystack) {
return preg_match('/' . preg_quote($needle, '/') . '$/', $haystack);
}
Cette question a déjà de nombreuses réponses, mais dans certains cas, vous pouvez vous contenter de quelque chose de plus simple. Si la chaîne que vous recherchez est connue (codée en dur), vous pouvez utiliser des expressions régulières sans guillemets, etc.
Vérifiez 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); // "preg_match('#/$#', $myPath); // Use "#" as delimiter instead of escaping slash
quot; here means end of string
Dans mon cas simple, je voulais vérifier si une chaîne de caractères se termine par une barre oblique:
<*> L'avantage: comme il est très court et simple, vous n'avez pas besoin de définir une fonction (telle que endsWith ()
) comme indiqué ci-dessus.
Mais encore une fois - ce n'est pas une solution pour chaque cas, juste celui très spécifique.
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 $ meule de foin n'a qu'un 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
Voici deux fonctions qui n'introduisent pas de chaîne temporaire, ce qui pourrait être utile lorsque les aiguilles sont très grosses:
function startsWith($haystack, $needle)
{
return strncmp($haystack, $needle, strlen($needle)) === 0;
}
function endsWith($haystack, $needle)
{
return $needle === '' || substr_compare($haystack, $needle, -strlen($needle)) === 0;
}
Je sais que cela est terminé, mais vous voudrez peut-être consulter strncmp car cela vous permet de mettre la longueur de la chaîne à comparer, donc:
function startsWith($haystack, $needle, $case=true) {
if ($case)
return strncasecmp($haystack, $needle, strlen($needle)) == 0;
else
return strncmp($haystack, $needle, strlen($needle)) == 0;
}
La solution la plus rapide endsWith ():
# Checks if a string ends in a string
function endsWith($haystack, $needle) {
return substr($haystack,-strlen($needle))===$needle;
}
Indice de 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();
Résultats de référence:
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
Des lignes simples simples à comprendre, sans expressions régulières.
startsWith () est simple.
function startsWith($haystack, $needle) {
return (strpos($haystack, $needle) === 0);
}
endsWith () utilise les strrev (): légèrement fantaisistes et lents:
function endsWith($haystack, $needle) {
return (strpos(strrev($haystack), strrev($needle)) === 0);
}
Voici une version multi-octets sécurisée de la réponse acceptée, elle fonctionne correctement pour les chaînes 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);
}
Si vous êtes sûr que les chaînes ne sont pas vides, ajouter un test sur le premier caractère, 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. Ajouter un autre test de caractère, comme $ haystack {1} === $ needle {1} ne semble pas accélérer beaucoup les choses, peut même ralentir.
===
semble plus rapide que ==
L'opérateur conditionnel (a)? B: c
semble plus rapide que si (a) b; sinon c;
Pour ceux qui demandent "pourquoi ne pas utiliser strpos?" appeler d'autres solutions "travaux inutiles"
strpos est rapide, mais ce n'est pas le bon outil pour ce travail.
Pour comprendre, voici une petite simulation à titre d'exemple:
Search a12345678c inside bcdefga12345678xbbbbb.....bbbbba12345678c
Qu'est-ce que l'ordinateur fait "à 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 totalité de la chaîne (mais même dans ce cas), cela n'est pas pratique du tout.
J'espère que la réponse ci-dessous sera efficace et 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';
Je finis généralement par utiliser une bibliothèque telle que 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
La bibliothèque regorge d’autres fonctions pratiques.
La réponse de mpen est incroyablement complet, mais, malheureusement, la référence fournie a une surveillance très importante et préjudiciable.
Parce que chaque octet dans les aiguilles et les meules de foin est complètement aléatoire, la probabilité qu’une paire aiguille-botte de faille diffère dès le tout premier octet est de 99,609375%, ce qui signifie qu'en moyenne, environ 99 609 des 100 000 paires diffèrent des tout premier octet. En d’autres termes, le repère est fortement biaisé en faveur de startswith
qui vérifient le premier octet de manière explicite, comme le fait strncmp_startswith2
.
Si la boucle génératrice de test est implémentée 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 référence racontent une histoire légèrement différente:
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, ce point de référence n’est peut-être pas toujours parfaitement impartial, mais il teste également l’efficacité des algorithmes lorsqu’on donne également des aiguilles partiellement adaptées.
La fonction substr
peut renvoyer false
dans de nombreux cas particuliers. Voici donc ma version, qui traite de ces problèmes:
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
}
Tests ( 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'));
De même, la fonction substr_compare
vaut également la peine d’être examiné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;
}
Cela peut fonctionner
function startsWith($haystack, $needle) {
return substr($haystack, 0, strlen($needle)) == $needle;
}
Pourquoi pas ce qui suit?
//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 valuehaystack!
N'oubliez pas que strpos
renverra la valeur false si l'aiguille n'a pas été trouvée dans la botte de foin, et renverra 0 si, et seulement si, l'aiguille a été trouvée à l'index 0 (AKA au début).
Et voici la fin avec:
$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, la fonction startsWith () n'est pas nécessaire car
(strpos($stringToSearch, $doesItStartWithThis) === 0)
retournera vrai ou faux avec précision.
Il semble étrange que ce soit aussi simple que cela avec toutes les fonctions sauvages qui sévissent ici.
Je le ferais comme ça
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; // ------------------------- speed boost!
return (0===substr_compare($haystack,$needle,0,strlen($needle)));
}
Cette ligne supplémentaire, comparant le premier caractère des chaînes, peut rendre le les faux cas retournent immédiatement , ce qui vous permet de faire beaucoup de comparaisons beaucoup plus vite (7 fois plus vite quand j'ai mesuré). Dans le cas réel, vous ne payez pratiquement aucun prix en termes de performances pour cette ligne unique, donc je pense que cela vaut la peine d'être inclus. (En outre, en pratique, lorsque vous testez plusieurs chaînes pour un morceau de départ spécifique, la plupart des comparaisons échouent, car dans un cas typique, vous recherchez quelque chose.)
Vous pouvez également utiliser des expressions régulières:
function endsWith($haystack, $needle, $case=true) {
return preg_match("/.*{$needle}$/" . (($case) ? "" : "i"), $haystack);
}
Beaucoup des réponses précédentes fonctionneront tout aussi bien. Cependant, ceci est peut-être aussi bref que vous pouvez le faire et qu’il fasse ce que vous désirez. Vous déclarez simplement que vous aimeriez que cela «retourne vrai». J'ai donc inclus des solutions qui renvoient booléen vrai / faux et le texte vrai / faux.
// 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';
}
D'après la réponse de James Black, en voici la version finale:
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);
}
Remarque: j'ai remplacé la partie if-else par la fonction startsWith de James Black, car strncasecmp est en fait la version de strncmp qui ne respecte pas la casse.
Voici une solution efficace pour PHP 4. Vous pourriez 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 toute la chaîne si elle ne correspond pas.
De plus, comme je ne vérifie pas les valeurs entières mais compare les chaînes, je ne dois pas nécessairement m'inquiéter 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 même mieux optimisé.
function startsWith($haystack,$needle) {
return substring($haystack,0,strlen($needle)) == $needle);
}
function endsWith($haystack,$needle) {
return substring($haystack,-strlen($needle)) == $needle);
}