PHP explotar la cadena, pero el tratamiento de palabras entre comillas como una sola palabra

StackOverflow https://stackoverflow.com/questions/2202435

Pregunta

¿Cómo puedo explotar la siguiente cadena:

Lorem ipsum "dolor sit amet" consectetur "adipiscing elit" dolor

en

array("Lorem", "ipsum", "dolor sit amet", "consectetur", "adipiscing elit", "dolor")

Para que el texto de la cita es tratado como una sola palabra.

Esto es lo que tengo por ahora:

$mytext = "Lorem ipsum %22dolor sit amet%22 consectetur %22adipiscing elit%22 dolor"
$noquotes = str_replace("%22", "", $mytext");
$newarray = explode(" ", $noquotes);

pero mi código divide cada palabra en una matriz. ¿Cómo puedo hacer que las palabras entre comillas tratadas como una sola palabra?

¿Fue útil?

Solución

Se puede usar un preg_match_all(...):

$text = 'Lorem ipsum "dolor sit amet" consectetur "adipiscing \\"elit" dolor';
preg_match_all('/"(?:\\\\.|[^\\\\"])*"|\S+/', $text, $matches);
print_r($matches);

que producirá:

Array
(
    [0] => Array
        (
            [0] => Lorem
            [1] => ipsum
            [2] => "dolor sit amet"
            [3] => consectetur
            [4] => "adipiscing \"elit"
            [5] => dolor
        )

)

Y como se puede ver, sino que también da cuenta de las cotizaciones escapado dentro de cadenas entre comillas.

Editar

A breve explicación:

"           # match the character '"'
(?:         # start non-capture group 1 
  \\        #   match the character '\'
  .         #   match any character except line breaks
  |         #   OR
  [^\\"]    #   match any character except '\' and '"'
)*          # end non-capture group 1 and repeat it zero or more times
"           # match the character '"'
|           # OR
\S+         # match a non-whitespace character: [^\s] and repeat it one or more times

Y en caso de coincidencia %22 en lugar de comillas dobles, que haría:

preg_match_all('/%22(?:\\\\.|(?!%22).)*%22|\S+/', $text, $matches);

Otros consejos

Esto habría sido mucho más fácil con str_getcsv() .

$test = 'Lorem ipsum "dolor sit amet" consectetur "adipiscing elit" dolor';
var_dump(str_getcsv($test, ' '));

Te da

array(6) {
  [0]=>
  string(5) "Lorem"
  [1]=>
  string(5) "ipsum"
  [2]=>
  string(14) "dolor sit amet"
  [3]=>
  string(11) "consectetur"
  [4]=>
  string(15) "adipiscing elit"
  [5]=>
  string(5) "dolor"
}

También puede intentar explotar esta función múltiple

function multiexplode ($delimiters,$string)
{

$ready = str_replace($delimiters, $delimiters[0], $string);
$launch = explode($delimiters[0], $ready);
return  $launch;
}

$text = "here is a sample: this text, and this will be exploded. this also | this one too :)";
$exploded = multiexplode(array(",",".","|",":"),$text);

print_r($exploded);

En algunas situaciones el pequeño token_get_all() podría resultar útil :

$tokens = token_get_all("<?php $text ?>");
$separator = ' ';
$items = array();
$item = "";
$last = count($tokens) - 1;
foreach($tokens as $index => $token) {
    if($index != 0 && $index != $last) {
        if(count($token) == 3) {
            if($token[0] == T_CONSTANT_ENCAPSED_STRING) {
                $token = substr($token[1], 1, -1);
            } else {
                $token = $token[1];
            }
        }
        if($token == $separator) {
            $items[] = $item;
            $item = "";
        } else {
            $item .= $token;
        }
    }
}

Resultados:

Array
(
    [0] => Lorem
    [1] => ipsum
    [2] => dolor sit amet
    [3] => consectetur
    [4] => adipiscing elit
    [5] => dolor
)

Vine aquí con un problema de la cuerda división compleja similar a este, pero ninguna de las respuestas aquí hice exactamente lo que quería - así que escribí mi propia

.

Me estoy publicando aquí sólo en caso de que sea útil a alguien más.

Esta es probablemente una manera muy lenta e ineficiente para hacerlo - pero funciona para mí

.
function explode_adv($openers, $closers, $togglers, $delimiters, $str)
{
    $chars = str_split($str);
    $parts = [];
    $nextpart = "";
    $toggle_states = array_fill_keys($togglers, false); // true = now inside, false = now outside
    $depth = 0;
    foreach($chars as $char)
    {
        if(in_array($char, $openers))
            $depth++;
        elseif(in_array($char, $closers))
            $depth--;
        elseif(in_array($char, $togglers))
        {
            if($toggle_states[$char])
                $depth--; // we are inside a toggle block, leave it and decrease the depth
            else
                // we are outside a toggle block, enter it and increase the depth
                $depth++;

            // invert the toggle block state
            $toggle_states[$char] = !$toggle_states[$char];
        }
        else
            $nextpart .= $char;

        if($depth < 0) $depth = 0;

        if(in_array($char, $delimiters) &&
           $depth == 0 &&
           !in_array($char, $closers))
        {
            $parts[] = substr($nextpart, 0, -1);
            $nextpart = "";
        }
    }
    if(strlen($nextpart) > 0)
        $parts[] = $nextpart;

    return $parts;
}

El uso es como sigue. explode_adv tarda 5 argumentos:

  1. Una matriz de caracteres que se pueden abrir un bloque - por ejemplo, [, (, etc.
  2. Una matriz de caracteres que cierran un bloque - por ejemplo, ], ), etc.
  3. Una matriz de caracteres que alternar un bloque - por ejemplo, ", ', etc.
  4. Una serie de caracteres que deberían provocar una escisión en la siguiente parte.
  5. La cadena a trabajar.

Este método probablemente tiene defectos - ediciones son bienvenidos

.
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top