2010-02-04 11 views
40

Come posso esplodere la seguente stringa:PHP esplodere la stringa, ma il trattamento di parole tra virgolette come un'unica parola

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

in

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

modo che il testo in citazione è trattata come un singola parola.

Ecco quello che ho per ora:

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

ma il mio codice divide ogni parola in un array. Come faccio a rendere le parole tra virgolette trattate come una parola?

+2

Sembra un lavoro per Regex – Earlz

+0

Vedere anche [Una funzione explode() che ignora i caratteri all'interno delle virgolette?] (Http://stackoverflow.com/questions/3264775/an-explode-function-that-ignores-characters -inside-quotes) – Bergi

risposta

79

si potrebbe usare un preg_match_all(...):

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

che produrrà:

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

) 

E come si può vedere, si spiega anche per le citazioni di escape all'interno stringhe tra virgolette.

EDIT

Una breve spiegazione:

"   # 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 

E in caso di corrispondenza %22 invece di virgolette, faresti:

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

C'è un motivo per non usare 'preg_split' invece di' preg_match_all'? sembra un IMO più naturale. – prodigitalson

+0

È fantastico! Dovrò studiare il codice per un po 'per capire cosa è successo! grazie – timofey

+2

@prodigitalson: no, usando 'preg_split (...)' non puoi tenere conto dei caratteri di escape. 'preg_match_all (...)' "si comporta" più come un parser che è la cosa più naturale da fare qui. Inoltre, usando un 'preg_split (...)', avrai bisogno di guardare avanti a ogni spazio per vedere quante virgolette ci sono davanti, rendendolo un'operazione 'O (n^2)': nessun problema per i piccoli stringhe, ma potrebbe diminuire il tempo di esecuzione quando sono coinvolte stringhe più grandi. –

62

Questo sarebbe stato molto più facile con str_getcsv().

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

Ti dà

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" 
} 
+0

Funziona sul mio computer di sviluppo, ma non sul mio server di produzione. : -/ –

+4

str_getcsv richiede PHP 5.3. – armakuni

+3

Ahh perché sto scoprendo questa funzione ?! –

4

Si può anche provare questa funzione multipla esplodere

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); 
+2

Questa risposta è buona, ma se la chiedi di dividere su spazi e preventivi, si divide su spazi all'interno delle virgolette. – starbeamrainbowlabs

1

In alcune situazioni il poco conosciuto token_get_all() potrebbe rivelarsi utile:

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

Resul ts:

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

Sono venuto qui con un complesso problema di stringa scissione simile a questo, ma nessuna delle risposte qui hanno fatto esattamente quello che volevo - così ho scritto il mio.

Vi metto qui solo nel caso in cui è utile a qualcun altro.

questo è probabilmente un modo molto lento e inefficiente per farlo - ma funziona per me.

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

L'utilizzo è come segue.explode_adv prende 5 argomenti

  1. Un array di caratteri che aprono un blocco - esempio [, (, ecc.
  2. Un array di caratteri che chiude un blocco - ad es. ], ), ecc.
  3. Un array di caratteri che commuta un blocco - ad es. ", ', ecc.
  4. Un array di caratteri che dovrebbe causare una divisione nella parte successiva.
  5. La stringa su cui lavorare.

Questo metodo ha probabilmente dei difetti - le modifiche sono benvenute.

Problemi correlati