Extracción de subcadena PHP. Obtenga la cadena antes de la primera '/' o la cadena completa

170

Estoy tratando de extraer una subcadena. Necesito ayuda para hacerlo en PHP.

Aquí hay algunas cadenas de muestra con las que estoy trabajando y los resultados que necesito:

home/cat1/subcat2 => home

test/cat2 => test

startpage => startpage

Quiero obtener la cadena hasta el primero /, pero si no/ hay presente, obtener toda la cadena.

Lo intenté,

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

Creo que dice: obtenga la posición de /y luego obtenga la subcadena de la posición 0 a esa posición.

No sé cómo manejar el caso donde no hay /, sin hacer que la declaración sea demasiado grande.

¿Hay alguna manera de manejar ese caso también sin hacer que la declaración de PHP sea demasiado compleja?


fuente
1
Puede ser s($str)->beforeFirst('/')útil, como se encuentra en esta biblioteca independiente .
caw

Respuestas:

261

Utilizar explode()

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

En este caso, estoy usando el limitparámetro para explodeque php no escanee la cadena más de lo necesario.

GNUD
fuente
2
+1 Gracias por la respuesta. Funcionó :) Pero una pregunta. Solo puedo hacer esto -> $arr = explode('/',$mystring,2); echo $arr[0];. No puedo obtener la primera cadena en una sola declaración - echo explode('/',$mystring,2)[0];. Como explotar devuelve una matriz, ¿debería poder hacerlo bien? Pero me sale un error. ¿Alguna sugerencia?
1
A Php no le gusta que indexes los valores de retorno de las funciones.
gnud
3
Oh. bueno. Hubiera sido agradable si fuera posible.
36
explode() + [0]es una manera larga de escribirstrtok($string, "/")
mario
55
por cierto, puedes hacer explotar ("/", $ string, 2) [0] en php 5.5
billynoah
293

La solución más eficiente es la strtokfunción:

strtok($mystring, '/')

Por ejemplo:

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

y

$mystring = 'home';
$first = strtok($mystring, '/');
echo $first; // home
jmarceli
fuente
25
Esto también es aproximadamente un 40% más rápido que la current-explodesolución. (No es que lo use tan a menudo que sea importante)
Towr
55
Esto es elegante y rápido, debería ser la respuesta aceptada.
Kosta Kontos
55
Esta debería ser la respuesta exceptuada. Definitivamente más rápido y más ciclos de memoria y CPU eficientes que cualquiera de las explodesoluciones dadas.
Shivam Maheshwari
El problema con strtokes first/secondvolverá firstpero /secondvolverá en secondlugar de una cadena vacía.
rybo111
Además de mi comentario anterior: El comportamiento cuando se encontró una pieza vacía cambió con PHP 4.1.0. El comportamiento anterior devolvió una cadena vacía, mientras que el comportamiento nuevo y correcto simplemente omite la parte de la cadena
rybo111
95
$first = explode("/", $string)[0];
AndyBrandy
fuente
2
elegante, pero no muy eficiente en tiempo de computadora. Pero en estos días la gente ya no se preocupa mucho por los minutos de ciclos de CPU
Dennis
13

¿Qué hay de esto?

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

Simplemente agregue un '/' al final de mystring para que pueda estar seguro de que hay al menos uno;)

IRCF
fuente
Puede verificar si hay una barra en la cadena antes de hacer esto. De todos modos, es la solución más simple.
Guilherme Sampaio
12

Versión de una línea de la respuesta aceptada:

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

Debería funcionar en php 5.4+

glifo
fuente
1
A diferencia del siguiente, el "2" limita el número de elementos de matriz que crea. Buen pensamiento.
Ben en CA
9

Este es probablemente el ejemplo más corto que se me ocurrió:

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

1) list()asignará automáticamente la cadena hasta "/"que se encuentre el delimitador
2) si "/"no se encuentra el delimitador, entonces se asignará toda la cadena

... y si realmente te obsesionas con el rendimiento, puedes agregar parámetros adicionales para explotar, lo explode("/", $mystring, 2)que limita el máximo de los elementos devueltos.

Pavlovich
fuente
2
Me gusta este enfoque. Ahorra haciendo una matriz innecesaria. Y strtok()no es seguro.
rybo111
1
@ rybo111: ¿Por qué no es seguro strtok()?
Hakre
@ rybo111 Me hago eco del sentimiento de Hakre; ¿Qué hace strtok()inseguro?
Doktor J
@hakre Ver mis respuestas a la respuesta de jmarceli. Puede causar un comportamiento inesperado dependiendo de la versión de PHP.
rybo111
php 4.1.0 - ¿realmente?
Hakre
8

Más vale tarde que nunca. php tiene una función predefinida para eso. Aquí está ese buen camino.

strstr

si desea obtener la parte antes del partido, simplemente configure before_needle (tercer parámetro) en 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', '/')
);
aimme
fuente
Esto no es seguro de usar si no puede estar seguro de que la aguja existe en la cuerda.
Fooquency
@fooquency: es cierto, pero siempre puede agregar el carácter al final de la cadena que está revisando, solo para estar seguro.
MikeSchinkel
Gracias. Mis pruebas mostraron que strstres un poco más rápido que strtok. Iré con el primero.
Ian Y.
5

La función strstr () en PHP 5.3 debería hacer este trabajo. Sin embargo, el tercer parámetro debe establecerse en verdadero.

Pero si no está utilizando 5.3, entonces la siguiente función debería funcionar con precisión:

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

Sin embargo, no lo he probado, pero esto debería funcionar bien ... Y también es bastante rápido

Ronald
fuente
3
+1 para strstr(), pero tenga en cuenta que devuelve falsesi la cadena no contiene $needle, por lo tanto, las explode()soluciones anteriores se ajustan mejor en este caso.
Benjamin
3

Puede crear una función auxiliar para encargarse de eso:

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

Aquí hay un caso de uso:

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

echo str_before($sing, '.'); // My name is Luka
Toby Speight
fuente
3

Puedes intentar usar una expresión regular como esta:

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

a veces, las expresiones regulares son más lentas, así que si el rendimiento es un problema, asegúrese de compararlo correctamente y use otra alternativa con subcadenas si es más adecuado para usted.

t00ny
fuente
2
Es probable que Regex también sea excesivo, pero como digo lo mismo explode, sería interesante ver cuál es más rápido.
rvighne
1
No hay absolutamente nada de malo en esto y no puedo pensar por qué merecería 2 votos negativos. Yo personalmente no usaría expresiones regulares, pero ciertamente no está mal.
billynoah
2

Usando currentel explodefacilitaría el proceso.

 $str = current(explode("/", $str, 2));
usuario1518659
fuente
0
$string="kalion/home/public_html";

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

También puede usar esta solución de una línea

list($substring) = explode("/", $string);
Mas
fuente
-1

¿Creo que esto debería funcionar?

substr($mystring, 0, (($pos = (strpos($mystring, '/') !== false)) ? $pos : strlen($mystring)));
Franz
fuente
Su función siempre devolverá el primer carácter porque está haciendo (strpos ($ mystring, '/')! == false) antes de asignarlo a $ pos, debe hacer un (($ pos = strpos ($ firstColumnName, '_'))! == falso). Este sería el trazador de líneas que busca el tipo que publicó la pregunta.
Mihai P.
-1

por qué no usar:

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

O:

   function getwhatiwant($s)
   {
       $delimiter='/';
       $t=explode($delimiter, $s);
       return ($t[1]?$t[0]:$s);
   }
usuario1123382
fuente