Regex per replace di un BBcode con parametri

skillsfactory

Utente Attivo
23 Nov 2012
50
0
0
salve ragazzi,
ho un bbcode che può avere diversi parametri (diciamo n parametri opzionali visto che è personalizzabile dall'utente). L'unico parametro che è sicuramente presente, perchè obbligatorio, è il parametro "id", per cui avro un codice di questo tipo:

Codice:
[bbcode param1='abc' param2='abc' id='IDCODE' param3='abc']testo opzionale etc.[/bbcode]

dovendo fare il replace di questo bbcode non riesco a scrivere una regola adatta a rimpiazzarlo tramite preg_replace().

ho provato ad esempio con:

PHP:
$testo = "questa è una stringa con bbcode [bbcode param1='abc' param2='abc' id='IDCODE' param3='abc']testo opzionale etc.[/bbcode]";
$id      = "IDCODE";
preg_replace("#\[bbcode(.*?)id='".$id."'(.*?)\](.*?)\[\/bbcode\]#",'è funziona perfettamente',$testo);

ovviamente non funziona... un altro tentativo è stato:
Codice:
#\[bbcode\s+id='".$chiave."'((.*?)!?\])(.*?)\[\/bbcode\]#

ma nulla...

vi ricordo le peculiarità del code:
- ha n parametri creati dall'utente
- ha sicuramente un parametro id di cui conosco il valore
- al suo interno è racchiuso del testo
- i valori dei parametri possono essere racchiusi sia tra apici ' ' che tra virgolette " "
- i prametri potrebbero essere separati da più spazi (vengono scritti dagli utenti e posso sbagliare)

qualche idea??? :)
 
Ultima modifica:
ciao
da quello che ho capito l'utente può fare quello che vuole, quindi secondo me più che una regex ti serve analizzare tutta la stringa.
io farei una funzione del tipo
PHP:
<?php
function analizza($testo){
	//riduci gli eventuali spazi in più
	$spazi=array("  ", "   ", "    ");//2, 3 , 4 spazi....
	$testo =str_replace($spazi, " ", $testo);
	//puoi toglere la chiusura tanto dovresti sapere che c'è e cosa è, eventualmente con un array come per gli spazi
	$testo =str_replace("[/bbcode]", "", $testo);
	$prima_dopo=explode("]",$testo);
	//$prima_dopo[1] conterrà il testo opzionale etc.
	//togli l'inizio del bbcode
	$prima_dopo[0]=str_replace("[bbcode", "", $prima_dopo[0]);
	//tolgo eventuali spazi sull =
	$uguale=array(' =','= ', ' = ');
	$prima_dopo[0]=str_replace($uguale, "=", $prima_dopo[0]);
	//tolgo eventuali spazi prima e dopo
	$prima_dopo[0]=trim($prima_dopo[0]);
	//estrai i parametri
	$parametri=explode(" ",$prima_dopo[0]);
	/*
	$parametri[0]=param1='abc'
	$parametri[1]=param2='abc'
	$parametri[2]=id='IDCODE'
	...ecc...
	*/
	//poi es se vuoi avere un array con nome parametro suo valore
	$par_array=array();
	$par_array[0]=$prima_dopo[1];
	foreach($parametri as $valore){
		$nome_val=explode("=",$valore);
		$par_array[$nome_val[0]]=$nome_val[1];
	}
	//poi dell'array ne fai quello che vuoi
	foreach($par_array as $chiave => $valore){
		if($valore ==""){//ripulisco di altri eventuali valori non validi
		/*potresti aggiungere se sai tutto l'elenco dei nomi dei parametri
		per ripulire da eventuali porcherie
		$nome=array('param1','param2',...ecc....);
		e nell' if aggiungere
		if($valore =="" || !in_array($chiave, $nome)){
		analogamente al posto di $valore =="" se sai quali valori puossono assumere i parametri
		if(!in_array($valore,$elenco) || !in_array($chiave, $nome)){
		*/
		unset($par_array[$chiave]);//elimino la porcheria
		}
	}
	return $par_array;
}
//..................
//test
$testo = "[bbcode param1='abc'   param2='abc'  id= 'IDCODE' param3='abc']testo opzionale etc.[/bbcode]";
$pulito=analizza($testo);
foreach($pulito as $ch => $val){
	echo "$ch: $val<br />";
}
?>
guarda che è un'idea da adattare alle tue esigenze
 
quella della funzione potrebbe essere una buona idea, tuttavia dovendo analizzare lunghe porzioni di codice ero orientato alla regex per avere un metodo molto più performante. Ti ringrazio cmq per la dritta! ;)

tuttavia la situazione è un pò più complessa e se hai giusto un altro minutino da dedicarmi, ti faccio un esempio pratico.

C'è un particolare bbcode che si chiama "traduci", composto da vari parametri tra cui l'id che corrisponde ad una chiave a cui corrisponde una traduzione per ogni lingua ed è più o meno formattato così (dico più o meno perchè l'utente potrebbe aggiungervi parametri).

Codice:
[traduci id="WELCOME_HOME" not="fr,de"]Benvenuto sul sito[/traduci]

l'id WELCOME_HOME dice al parser che deve sostituire "benvenuto sul sito" (o meglio tutto i bbcode) con la traduzione in lingua del visitatore salvata sotto la chiave WELCOME_HOME (le traduzioni sono in un db dove l'id è la chiave della tabella). il parametro "not" dice ad esempio che in francese (fr) e tedesco (de) quel messaggio non deve essere visualizzato (ma questo non è importante è giusto per capire che ci sono altri parametri).

La cosa importante è che il parser deve trovare quel tag, indipendentemente dalla sua formattazione (parametri, valori dei parametri opzionali, spazi in più etc.), sapendo che sicuramente c'è un id di cui conosco la chiave, e sostituirlo con la variante tradotta.

Banalmente per capirci, è come se dovessi fare questo:

PHP:
    $str = '[traduci id="WELCOME_HOME" not="fr,de"]benvenuto sul sito[/traduci]';
    echo str_replace('[traduci id="WELCOME_HOME" not="fr,de"]benvenuto sul sito[/traduci]','Welcome Site',$str);

ma senza dovermi preoccupare di avere la corrispondenza esatta.... quindi passare al metodo preg_replace con un espressione regolare è l'ideale, si tratta solo di scrivere bene la regola del tipo:

[traduci{qui ci può stare qualsiasi cosa}id="WELCOME_HOME"{qui ci può stare qualsiasi cosa}]{qui ci può stare qualsiasi cosa}[/traduci]

Ad esempio, se avessi questa situazione

PHP:
<?php
$str = '[traduci id=\'HELLO\']ciao[/traduci][traduci  id=\'HELLO\'   not=\'fr\' ]ciao[/traduci][traduci not="fr" id="HELLO"]ciao[/traduci][traduci   not="fr"   id="HELLO" param="abc"]ciao[/traduci]';

// traduco in francese
echo preg_replace("#\[traduci\s+id='HELLO'((.*?)!?\])(.*?)\[\/traduci\]#","SALUT",$str);
?>

otterrei come risultato (qui in opera: http://codepad.org/eI4FBzZO )

Codice:
SALUTSALUT[traduci not="fr" id="HELLO"]ciao[/traduci][traduci   not="fr"   id="HELLO"  param="abc"]ciao[/traduci]

cioè funziona ovviamente solo il primo e il secondo perchè rispettano la regola... a me semplicemente servirebbe una regola più snella, che funzioni in tutti e quattro i casi...
 
Ultima modifica:
come nn detto... soluzione trovata

PHP:
<?php
$chiavi = array('C1','C2','C3','C4','C5');

$str = '[traduci id=\'C1\']ciao[/traduci][traduci  id=\'C2\'   not=\'fr\' ]ciao[/traduci][traduci not="fr" id="C3"]ciao[/traduci][traduci   not="fr"   id="C4" param="abc"]ciao[/traduci][TRADUCI not="fr"  ONLY="sdcs"  id="C5" param="abc" dsfdsf="sdsf"]ciao[/traduci]';

// traduco in francese
foreach($chiavi as $chiave)
$str = preg_replace("#\[traduci(.*?)id=['|\"]".$chiave."['|\"](.*?)\](.*?)\[\/traduci\]#i","SALUT-".$chiave." | ",$str);

echo $str;
?>

http://codepad.org/8Nwtzr4B
 

Discussioni simili