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
Était-ce utile?

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

startswith_benchmark.php

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 :

Vérifier si une chaîne se termine par une autre chaîne

Vérifier si une chaîne commence par une autre chaîne

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

Vous pouvez utiliser strpos et strrpos

$bStartsWith = strpos($sHaystack, $sNeedle) == 0;
$bEndsWith = strrpos($sHaystack, $sNeedle) == strlen($sHaystack)-strlen($sNeedle);

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;
}

Source: https://stackoverflow.com/a/4419658

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);
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top