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
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 une expression régulière.
Vous pouvez utiliser la fonction substr_compare
pour vérifier les débuts et les fins:
_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;
}
_
Cela 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 les débuts avec, mais il ne peut pas vérifier les fins avec.
Mis à jour le 23 août 2016
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";
}
(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
(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
Jusqu'à présent, toutes les réponses semblent faire beaucoup 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 à :
La regex fonctionne 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 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 de caractères se termine par une barre oblique:
preg_match('#/$#', $myPath); // Use "#" as delimiter instead of escaping slash
L'avantage: comme c'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-ci 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 $ haystack ne contient 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 réalise que ceci est terminé, mais vous voudrez peut-être regarder 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;
}
# 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
Lignes simples, faciles à 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 certain que les chaînes ne sont pas vides, ajouter un test sur le premier caractère, avant la comparaison, la chaîne, etc. accélère un peu les choses:
function startswith5b($haystack, $needle) {
return ($haystack{0}==$needle{0})?strncmp($haystack, $needle, strlen($needle)) === 0:FALSE;
}
C'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 ==
Opérateur conditionnel (a)?b:c
semble plus rapide que if(a) b; else c;
Pour ceux qui demandent "pourquoi ne pas utiliser strpos?" Appelant d'autres solutions "travail inutile"
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 chaîne entière (mais même dans ce cas), cela n'est pas du tout pratique.
Je finis généralement par aller avec une bibliothèque comme nderscore-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 utiles.
Le réponse by mpen est incroyablement complet, mais, malheureusement, le repère fourni fournit une surveillance très importante et préjudiciable.
Comme chaque octet d'aiguilles et de meules de foin est complètement aléatoire, la probabilité qu'une paire aiguille-meule de foin diffère dès le premier octet est de 99,609375%, ce qui signifie qu'en moyenne, environ 99 609 des 100 000 paires diffèrent le premier octet. . En d'autres termes, le repère est fortement biaisé vers les implémentations 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, cette référence peut ne pas toujours être parfaitement impartiale, mais elle teste également l'efficacité des algorithmes lorsque des aiguilles partiellement appariées sont également fournies.
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';
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 renvoyer la casse fausse immédiatement, rendant ainsi beaucoup de vos comparaisons beaucoup plus rapides (7 fois plus rapidement lorsque 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 de nombreuses chaînes pour un morceau de départ spécifique, la plupart des comparaisons échoueront car, dans un cas typique, vous recherchez quelque chose.)
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!
Gardez à l'esprit, strpos
retournera false si l'aiguille n'a pas été trouvée dans la botte de foin, et retournera 0 si, et seulement si, l'aiguille a été trouvée à l'indice 0 (AKA au début).
Et voici la finAvec:
$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, une fonction startsWith () n'est pas nécessaire.
(strpos($stringToSearch, $doesItStartWithThis) === 0)
retournera vrai ou faux avec précision.
Cela semble étrange, c'est aussi simple que cela avec toutes les fonctions sauvages qui sévissent ici.
Cela peut fonctionner
function startsWith($haystack, $needle) {
return substr($haystack, 0, strlen($needle)) == $needle;
}
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 bien):
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 plus, la fonction substr_compare
vaut également la peine d'être regardé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;
}
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;
}
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 tout aussi bien. Cependant, c'est peut-être aussi court que vous pouvez le faire et le faire faire ce que vous désirez. Vous dites simplement que vous aimeriez que cela "retourne vrai". J'ai donc inclus des solutions qui renvoient le 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';
}
Basé sur 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 respecte la casse.
Voici une solution efficace pour PHP 4. Vous pourriez obtenir des résultats plus rapides si vous utilisiez 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;
}
Pas de copie ni de boucle interne:
function startsWith($string, $start)
{
return strrpos($string, $start, -strlen($string)) !== false;
}
function endsWith($string, $end)
{
return ($offset = strlen($string) - strlen($end)) >= 0
&& strpos($string, $end, $offset) !== false;
}