2016-04-04 43 views
6

IMPORTANTE MODIFICA: Poiché molte persone hanno detto che questo dovrebbe essere evitato e quasi impossibile da usare con RegEx, ho intenzione di concederti qualche altra soluzione. A partire da ora, qualsiasi soluzione potrebbe essere utilizzata come risposta e infine come soluzione. Grazie!Deep (infinito) NESTED parole divise usando regex

Diciamo che ho:

$line = "{ It is { raining { and streets are wet } | snowing { and streets are { slippy | white }}}. Tomorrow will be nice { weather | walk }. }" 

output desiderato:

It is raining and streets are wet. Tomorrow will be nice weather. 
It is raining and streets are wet. Tomorrow will be nice walk. 
It is snowing and streets are slippy. Tomorrow will be nice weather. 
It is snowing and streets are slippy. Tomorrow will be nice walk. 
It is snowing and streets are white. Tomorrow will be nice weather. 
It is snowing and streets are white. Tomorrow will be nice walk. 

Con il codice da this answer alla mia precedente interrogazione, sono attualmente in grado di dividere le parole, ma non riesco a capire fuori i valori nidificati. Qualcuno potrebbe aiutarmi con quello che ho urlato. Sono abbastanza sicuro che dovrei implementare un ciclo for da qualche parte per farlo funzionare ma non riesco a capire dove.

$line = "{This is my {sentence|statement} I {wrote|typed} on a {hot|cold} {day|night}.}"; 
$matches = getMatches($line); 
printWords([], $matches, $line); 


function getMatches(&$line) { 
    $line = trim($line, '{}'); 
    $matches = null; 
    $pattern = '/\{[^}]+\}/'; 

    preg_match_all($pattern, $line, $matches); 

    $matches = $matches[0]; 

    $line = preg_replace($pattern, '%s', $line); 

    foreach ($matches as $index => $match) { 
     $matches[$index] = explode('|', trim($match, '{}')); 
    } 

    return $matches; 
} 


function printWords(array $args, array $matches, $line) { 
    $current = array_shift($matches); 
    $currentArgIndex = count($args); 

    foreach ($current as $word) { 
     $args[$currentArgIndex] = $word; 

     if (!empty($matches)) { 
       printWords($args, $matches, $line); 
     } else { 
       echo vsprintf($line, $args) . '<br />'; 
     } 
    } 
} 

Un modo ho ottenuto nella mia mente sta usando lexer tecnica, come nella lettura char da char, creare bytecode appropriate e quindi ciclo attraverso di essa. Non è regex ma dovrebbe funzionare.

+0

L'output desiderato è quello che hai postato o quello che produci attualmente? – Parfait

+0

L'output sopra riportato è ciò che voglio ottenere, la procedura corrente funziona per una linea non annidata. Controlla $ $ variabile all'interno della funzione. –

+0

Non penso che l'output previsto sia corretto. Il '| la parte 'nevica' è una OR con il precedente blocco '{...}' e l'output non sembra seguire quella regola. Detto diversamente: non sembra essere un modo algoritmico per passare dal tuo input all'output desiderato. –

risposta

1

Questa classe fa il lavoro, allthough non è sicuro quanto efficiente sia:

class Randomizer { 

    public function process($text) { 
     return preg_replace_callback('/\{(((?>[^\{\}]+)|(?R))*)\}/x', array($this, 'replace'), $text); 
    } 

    public function replace($text) { 
     $text = $this->process($text[1]); 
     $parts = explode('|', $text); 
     $part = $parts[array_rand($parts)]; 
     return $part; 
    } 
} 

Per utilizzarlo è sufficiente fare:

$line = "{This is my {sentence|statement} I {wrote|typed} on a {hot|cold} {day|night}.}"; 
$randomizer = new Randomizer(); 
echo $randomizer->process($line); 

Io non sono il migliore quando si tratta di regolare espressioni quindi non posso davvero spiegare perché quella particolare regex funzioni, mi dispiace per quello.

A proposito, restituisce stringhe casuali e non tutte le stringhe possibili. Fammi sapere se hai bisogno di tutte le stringhe invece di una casuale. Aggiornerò la risposta ..

+0

Grazie per il contributo ma questo non è quello che sto cercando. Lo script che ho già postato sta lavorando per produrre tutte le possibili variazioni della variabile '$ line' (che devo), ma la mia soluzione non funziona per valori annidati. Leggi di nuovo il post, il '{my {words | frase} | il tuo} dovrebbe essere possibile. –

+0

@ J.Doe Ho eseguito '{my {words | frase} | il tuo} 'e le uscite possibili erano' mie parole', 'tue',' mia frase'. Non è l'uscita corretta? – Gogol

+0

@ J.Doe la soluzione che ho postato funziona per natexx nested a livello .. – Gogol