Extraction de sous-chaînes PHP. Récupère la chaîne avant le premier «/» ou la chaîne entière


170

J'essaye d'extraire une sous-chaîne. J'ai besoin d'aide pour le faire en PHP.

Voici quelques exemples de chaînes avec lesquelles je travaille et les résultats dont j'ai besoin:

home/cat1/subcat2 => home

test/cat2 => test

startpage => startpage

Je veux obtenir la chaîne jusqu'au premier /, mais si aucun /n'est présent, récupère la chaîne entière.

J'ai essayé,

substr($mystring, 0, strpos($mystring, '/'))

Je pense que cela dit - obtenir la position de /, puis obtenir la sous-chaîne de la position 0 à cette position.

Je ne sais pas comment gérer le cas où il n'y en a pas /, sans rendre la déclaration trop grande.

Existe-t-il un moyen de gérer ce cas également sans rendre l'instruction PHP trop complexe?


1
Vous pourriez trouver s($str)->beforeFirst('/')utile, comme trouvé dans cette bibliothèque autonome .
caw

Réponses:


261

Utilisation explode()

$arr = explode("/", $string, 2);
$first = $arr[0];

Dans ce cas, j'utilise le limitparamètre to explodeafin que php ne scanne pas la chaîne plus que ce qui est nécessaire.


2
+1 Merci pour la réponse. Cela a fonctionné :) Mais une question. Je ne peux le faire que -> $arr = explode('/',$mystring,2); echo $arr[0];. Je ne parviens pas à obtenir la première chaîne dans une instruction elle-même - echo explode('/',$mystring,2)[0];. Puisque exploser renvoie un tableau, je devrais être capable de le faire correctement? Mais j'obtiens une erreur. Aucune suggestion?

1
Php n'aime pas que vous indexiez les valeurs de retour des fonctions.
gnud

3
Oh. d'accord. aurait été bien si c'était possible.

36
explode() + [0]est une façon fastidieuse d'écrirestrtok($string, "/")
mario

5
en passant, vous pouvez faire exploser ("/", $ string, 2) [0] en php 5.5
billynoah

293

La solution la plus efficace est la strtokfonction:

strtok($mystring, '/')

Par exemple:

$mystring = 'home/cat1/subcat2/';
$first = strtok($mystring, '/');
echo $first; // home

et

$mystring = 'home';
$first = strtok($mystring, '/');
echo $first; // home

25
C'est également environ 40% plus rapide que la current-explodesolution. (Non pas que je l'utilise si souvent que cela compte.)
vers

5
C'est élégant et rapide - devrait être la réponse acceptée.
Kosta Kontos

5
Cela devrait être la réponse exceptée. Définitivement plus rapide et plus de cycles de mémoire et de processeur efficaces que toutes les explodesolutions proposées.
Shivam Maheshwari

Le problème avec strtokest first/secondretournera firstmais /secondretournera secondplutôt qu'une chaîne vide.
rybo111 le

Suite à mon commentaire ci-dessus: le comportement lorsqu'une partie vide a été trouvée a changé avec PHP 4.1.0. L'ancien comportement a renvoyé une chaîne vide, tandis que le nouveau comportement correct ignore simplement la partie de la chaîne
rybo111

95
$first = explode("/", $string)[0];

2
élégant, mais pas très efficace en temps informatique. Mais ces jours-ci, les gens ne se soucient plus beaucoup des cycles de processeur minute
Dennis

13

Et ça :

substr($mystring.'/', 0, strpos($mystring, '/'))

Ajoutez simplement un '/' à la fin de mystring pour être sûr qu'il y en a au moins un;)


Vous pouvez simplement vérifier s'il y a une barre oblique dans la chaîne avant de faire cela. Quoi qu'il en soit, c'est la solution la plus simple.
Guilherme Sampaio

12

Version en une ligne de la réponse acceptée:

$out=explode("/", $mystring, 2)[0];

Devrait fonctionner en PHP 5.4+


1
Contrairement à celui ci-dessous, le "2" limite le nombre d'éléments de tableau qu'il crée. Bien pensé.
Ben en Californie

9

C'est probablement l'exemple le plus court qui m'est venu à l'esprit:

list($first) = explode("/", $mystring);

1) list()attribuera automatiquement la chaîne jusqu'à ce "/"que le délimiteur soit trouvé
2) si le délimiteur "/"n'est pas trouvé, la chaîne entière sera affectée

... et si vous êtes vraiment obsédé par les performances, vous pouvez ajouter un paramètre supplémentaire pour exploser explode("/", $mystring, 2)qui limite le maximum des éléments retournés.


2
J'aime cette approche. Enregistre la création d'un tableau inutile. Et strtok()c'est dangereux.
rybo111 le

1
@ rybo111: Qu'est-ce qui est dangereux strtok()?
hakre

@ rybo111 Je fais écho au sentiment de Hakre; qu'est-ce qui rend strtok()dangereux?
Doktor J

@hakre Voir mes réponses à la réponse de jmarceli. Cela peut provoquer un comportement inattendu selon la version de PHP.
rybo111 le

php 4.1.0 - rly?
hakre

8

Mieux vaut tard que jamais. php a une fonction prédéfinie pour cela. voici ce bon moyen.

strstr

si vous voulez obtenir la partie avant la correspondance, définissez simplement before_needle (3e paramètre) sur true http://php.net/manual/en/function.strstr.php

function not_strtok($string, $delimiter)
{    
    $buffer = strstr($string, $delimiter, true);

    if (false === $buffer) {
        return $string;
    }

    return $buffer;
}

var_dump(
    not_strtok('st/art/page', '/')
);

Ce n'est pas sûr à utiliser si vous ne pouvez pas être sûr que l'aiguille existe dans la chaîne.
fréquence du

@fooquency - Vrai, mais vous pouvez toujours ajouter le caractère à la fin de la chaîne que vous vérifiez, juste pour être sûr.
MikeSchinkel

Merci. Mes tests ont montré que strstrc'est légèrement plus rapide que strtok. J'irai avec le premier.
Ian Y.23

5

La fonction strstr () de PHP 5.3 devrait faire ce travail. Le troisième paramètre doit cependant être défini sur true.

Mais si vous n'utilisez pas 5.3, la fonction ci-dessous devrait fonctionner correctement:

function strbstr( $str, $char, $start=0 ){
    if ( isset($str[ $start ]) && $str[$start]!=$char ){
        return $str[$start].strbstr( $str, $char, $start+1 );
    }
}

Cependant, je ne l'ai pas testé, mais cela devrait très bien fonctionner. Et c'est assez rapide aussi


3
+1 pour strstr(), mais sachez qu'il retourne falsesi la chaîne ne contient pas $needle, donc les explode()solutions ci-dessus conviennent mieux dans ce cas.
Benjamin

3

Vous pouvez créer une fonction d'assistance pour vous en occuper:

/**
 * Return string before needle if it exists.
 *
 * @param string $str
 * @param mixed $needle
 * @return string
 */
function str_before($str, $needle)
{
    $pos = strpos($str, $needle);

    return ($pos !== false) ? substr($str, 0, $pos) : $str;
}

Voici un cas d'utilisation:

$sing = 'My name is Luka. I live on the second floor.';

echo str_before($sing, '.'); // My name is Luka

3

Vous pouvez essayer d'utiliser une expression régulière comme celle-ci:

$s = preg_replace('|/.*$|', '', $s);

parfois, les expressions régulières sont plus lentes, donc si les performances sont un problème, assurez-vous de les comparer correctement et utilisez une autre alternative avec des sous-chaînes si cela vous convient mieux.


2
Regex est probablement exagéré aussi, mais comme je dis la même chose, explodeil serait intéressant de voir lequel est le plus rapide.
rvighne

1
il n'y a absolument rien de mal à cela et je ne vois pas pourquoi cela mériterait 2 votes négatifs. Personnellement, je n'utiliserais pas regex mais ce n'est certainement pas faux.
billynoah le

2

Utiliser currentsur explodefaciliterait le processus.

 $str = current(explode("/", $str, 2));

0
$string="kalion/home/public_html";

$newstring=( stristr($string,"/")==FALSE ) ? $string : substr($string,0,stripos($string,"/"));

0

Vous pouvez également utiliser cette solution en une ligne

list($substring) = explode("/", $string);

-1

Je pense que cela devrait fonctionner?

substr($mystring, 0, (($pos = (strpos($mystring, '/') !== false)) ? $pos : strlen($mystring)));

Votre fonction retournera toujours le premier caractère car vous faites (strpos ($ mystring, '/')! == false) avant de l'affecter à $ pos, vous devez faire un (($ pos = strpos ($ firstColumnName, '_'))! == false). Ce serait la 1 doublure recherchée par le type qui a posé la question.
Mihai P.

-1

pourquoi ne pas utiliser:

function getwhatiwant($s)
{
    $delimiter='/';
    $x=strstr($s,$delimiter,true);
    return ($x?$x:$s);
}

OU:

   function getwhatiwant($s)
   {
       $delimiter='/';
       $t=explode($delimiter, $s);
       return ($t[1]?$t[0]:$s);
   }
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.