preg_replace_callback para reemplazar en cadena

M

Tengo el siguiente código para reemplazar expresiones por sus sinónimos en una cadena:


  $sinonimos=array('sin embargo' => array('no obstante', 'pero', 'de todas formas','de cualquier manera','en algún modo','como todo el mundo sabe'));
 
   $a='te lo digo sin embargo yo estoy aquí sin embargo yo te lo digo veces sin embargo mas je je je'; 
	   
$cambiar='sin embargo'; $b=preg_replace_callback("/$cambiar/i", create_function('$m', 'global $sinonimos; $p=strtolower(trim($m[0])); return array_key_exists($p, $sinonimos)?(is_array($sinonimos[$p])?X.$sinonimos[$p][mt_rand(0, count($sinonimos[$p])-1)].X:$sinonimos[$p]):$p;'), $a); print $b;

El problema se me plantea principalmente por dos razones;

1.En primer lugar mi array $sinonimos no es bidimensional, es del tipo
$sinonimos=array('sin embargo','no obstante', 'pero', 'de todas formas','de cualquier manera','en algún modo','como todo el mundo sabe');

2.En segundo lugar me gustaría que los reemplazos tuvieran el siguiente formato [b]{palabra buscada} [palabra sinónimo][/b] en negrita también y delimitadas por llaves y corchetes, es decir que [b]colocara ambas palabras[/b] juntas, sinónimo y original separadas por un espacio y si fuera posible [b]en negrita[/b].

Y por más que hago cambios e intentos no acierto a hacer el adecuado para que ambas cosas funcionen

¿podríais ayudarme? gracias de antemano

LOc0

Hola. El apaño es sencillo:

<?php
	
$sinonimos=array('sin embargo' , 'no obstante', 'pero', 'de todas formas','de cualquier manera','en algún modo','como todo el mundo sabe');

$a='te lo digo sin embargo yo estoy aquí sin embargo yo te lo digo veces sin embargo mas je je je';

$b=preg_replace_callback("/$sinonimos[0]/i", create_function('$m', 'global $sinonimos; $p=strtolower(trim($m[0])); return count($sinonimos>1)?"<b>{".$p."}[".$sinonimos[mt_rand(1, count($sinonimos)-1)]."]</b>":$p;'), $a);

var_dump($b);
?>

Salu2 ;)

PD: en lo sucesivo no abras otro hilo.

M

Muchas gracias, de verdad, pero creo que no me he explicado bien. En realidad tengo multiples arrays para detectar cada una de las diferentes expresiones.

Algo así:


   $sinonimos[1]=array('mas' , 'empero','otra vez');

  $sinonimos[2]=array('sin embargo' , 'no obstante', 'pero', 'de todas formas','de cualquier manera','en algún modo','como todo el mundo sabe');

De la manera en que lo has resuelto, (brillantemente por cierto) solo me detecta "sin embargo", pero no los demás (por ejemplo "mas")...

Mira, para que lo entiendas mejor; creé una consulta a una base de datos:


$consulta_mysql="select * from conectores"; //Consultar la base de datos

$resultado_consulta_mysql=mysql_query($consulta_mysql,$conn); //Envia una consulta MySQL
 
while($registro=mysql_fetch_array($resultado_consulta_mysql))//Devuelve un array que corresponde a la fila recuperada, o falso si no quedan más filas

			{
$registros[$pos] = $registro['palabra'].','.$registro['sinonimos']; //convertimos las líneas de conectores en un array de registros
$conectores[$pos] = explode (',',$registros[$pos]);   //ESTE ES EL ARRAY DE SINÓNIMOS.

$pos++;
	}

LOc0
<?php

$consulta_mysql="select * from conectores"; //Consultar la base de datos

$resultado_consulta_mysql=mysql_query($consulta_mysql,$conn); //Envia una consulta MySQL

$todos_los_sinonimos=array();

while(($registro=mysql_fetch_array($resultado_consulta_mysql)))
{
	$todos_los_sinonimos[strtolower(trim($registro['palabra']))] = explode(',', $registro['sinonimos']);
}
	
?>
<?php
           
$todos_los_sinonimos=array('sin embargo' => array('no obstante', 'pero', 'de todas formas'), 'yo' => array('el menda', 'robocop', 'el que manda')); $a='te lo digo sin embargo yo estoy aquí sin embargo yo te lo digo veces sin embargo mas je je je'; foreach($todos_los_sinonimos as $palabra => $sinonimos) { $a=preg_replace_callback("/$palabra/i", create_function('$p', 'global $sinonimos; return count($sinonimos)>1?"<b>{".$p[0]."}[".$sinonimos[mt_rand(0, count($sinonimos)-1)]."]</b>":$p[0];'), $a); } var_dump($a); ?>

Salu2 ;)

M

....pero???

M

....pero como logro que haga todos los reemplazo en el mismo texto???

esto es lo que me devuelve el código:

string(93) "te lo digo sin embargo yo estoy aquí sin embargo yo te lo digo veces sin embargo mas je je je" string(93) "te lo digo sin embargo yo estoy aquí sin embargo yo te lo digo veces sin embargo mas je je je" string(93) "te lo digo sin embargo yo estoy aquí sin embargo yo te lo digo veces sin embargo mas je je je" string(110) "te lo digo sin embargo yo estoy aquí sin embargo yo te lo digo veces sin embargo {mas}[empero] je je je" string(93) "te lo digo sin embargo yo estoy aquí sin embargo yo te lo digo veces sin embargo mas je je je" string(93) "te lo digo sin embargo yo estoy aquí sin embargo yo te lo digo veces sin embargo mas je je je" string(93) "te lo digo sin embargo yo estoy aquí...

...y sigue

LOc0

No entiendo.

spoiler

Está probado y me devuelve:

string(198) "te lo digo <b>{sin embargo}[no obstante]</b> <b>{yo}[el menda]</b> estoy aquí <b>{sin embargo}[pero]</b> <b>{yo}[el que lo parte]</b> te lo digo veces <b>{sin embargo}[no obstante]</b> mas je je je"

Salu2 ;)

M

Sii! ahora está bien, debía haber antes algún fallo. El problema es que incluso en los reemplazos ya realizados vuelve a hacer otros nuevos reemplazos sobre los mismos.

te lo digo {sin embargo}[además] yo estoy aquí {sin embargo}[por otro lado] yo te lo digo veces {sin embargo}[por otro lado] {mas}[{em{pero}[en cambio]}[{sin embargo}[asimismo]]] je je je 

¿Habría alguna forma de que respete el texto que está entre corchetes y llaves?

Por cierto!! si pasas por Cáceres, te debo unas cañas ;)

LOc0

Saltamos al final...

Salu2 ;)

M

Quizás también el problema está en que detecta fragmentos de palabras (por ejemplo "pero" de "empero") y hay que ver la manera de que las respete. En esta solución sigue sin respetar lo que está entre corchetes y detecta trozos de otras palabras si digo "emperonete" toma "empero" y lo cambia

LOc0

A ver si hay suerte:

    <?php
               
$todos_los_sinonimos=array('sin embargo' => array('no obstante', 'pero', 'de todas formas'), 'yo' => array('el menda', 'robocop', 'el que manda')); $a='te lo digo sin embargo yo estoy aquí sin embargo yo te lo digo veces sin embargo mas je je je'; foreach($todos_los_sinonimos as $palabra => $sinonimos) { $a=preg_replace_callback('/(?<![{\[a-zñ])'.$palabra.'(?![}\]a-zñ])/i', create_function('$p', 'global $sinonimos; return count($sinonimos)>0?"<b>{".$p[0]."}[".$sinonimos[mt_rand(0, count($sinonimos)-1)]."]</b>":$p[0];'), $a); } var_dump($a); ?>

http://en.wikipedia.org/wiki/Extreme_programming xD

Salu2 ;)

M

Toni eres un máquina, te la debo ;) se ve que le dedicas horas

Búscame en facebook por Txema Nigthlife

LOc0

Gracias, pero en este foro soy un "tuerto" más ;) Y sí, son muchas horas, demasiadas quizás ¬ ¬...

Hasta otra.

Salu2 ;)

M

Un último detalle... sigue sin respetar lo que está entre corchetes, sin el término está en la base de datos, lo busca y lo remplaza

{mas} [{pero} [al contrario]] 

Lo que está entre corchetes es lo que acaba de reemplazar

LOc0

No entiendo... No debería sustituir nada que esté entre [], {} o dentro de una palabra más larga...

¿Puedes ponerme un ejemplo más largo?

A mi me sale esto (fíjate en el array de sinónimos):

<?php

$todos_los_sinonimos=array('sin embargo' => array('pero'), 'pero' => array('no obstante', 'sin embargo', 'aún así'));

$a='te lo digo sin embargo yo estoy aquí sin embargo yo te lo digo veces sin embargo mas je je je';

foreach($todos_los_sinonimos as $palabra => $sinonimos)
	$a=preg_replace_callback('/(?<![{\[a-zñ])'.$palabra.'(?![}\]a-zñ])/i', create_function('$p', 'global $sinonimos; return count($sinonimos)>0?"<b>{".$p[0]."}[".$sinonimos[mt_rand(0, count($sinonimos)-1)]."]</b>":$p[0];'), $a);

var_dump($a);

?>

string(139) "te lo digo <b>{sin embargo}[pero]</b> yo estoy aquí <b>{sin embargo}[pero]</b> yo te lo digo veces <b>{sin embargo}[pero]</b> mas je je je"

Hace primero el cambio de todos los "sin embargo" por "pero" y luego no vuelve a cambiar los "pero" por nada.

Salu2 ;)

M

Sí que respeta lo que está entre corchetes, es cuando realiza el reemplazo cuando no lo respeta. Por lo que veo si ese término reemplazado tiene sinónimos vuelve a reemplazarlo

te lo digo [sin embargo] yo emperonete estoy aquí {sin embargo} [por otro lado] yo te lo digo veces {sin embargo} [por otro lado] {mas} [{empero} [{sin embargo} [por otro lado]]] je je je 

mira el fragmento

{mas} [{empero} [{sin embargo} [por otro lado]]]

asígnale sinónimos a los sinónimos y verás...

LOc0

Ponme el array de sinónimos que usas y la cadena que le metes.

Salu2 ;)

M

UUFF... tengo un montón en la base de datos, pero tus deseos son órdenes...

Para entenderlo mejor asígnale sinónimos a los sinónimos y verás...

La cadena:

      
$a='te lo digo [sin embargo] yo emperonete estoy aquí sin embargo yo te lo digo veces sin embargo mas je je je';

El peaso de array o arrays


Array ( [se trata de] => Array ( [0] => se relaciona [1] => está relacionado ) [con] => Array ( [0] => junto con [1] => al mismo tiempo que ) [electrico] => Array ( [0] => electrógeno [1] => galvánico [2] => electrizante [3] => dieléctrico ) [mas] => Array ( [0] => pero [1] => empero [2] => si bien [3] => no obstante ) [empero] => Array ( [0] => pero [1] => mas [2] => no obstante [3] => sin embargo ) [aunque] => Array ( [0] => apesar de que [1] => no obstante [2] => si bien [3] => sin embargo [4] => pese a que ) [por que] => Array ( [0] => ya que [1] => dadoque [2] => puesto que [3] => visto que [4] => debido a que [5] => pues que ) [pues] => Array ( [0] => puesto que [1] => luego [2] => por lo tanto [3] => ya que [4] => por consiguiente [5] => en vista de que ) [para empezar] => Array ( [0] => ante todo [1] => en primer lugar ) [ante todo] => Array ( [0] => para empezar [1] => en primer lugar ) [en primer lugar] => Array ( [0] => para empezar [1] => ante todo ) [para añadir] => Array ( [0] => y [1] => finalmente [2] => en otras palabras [3] => además [4] => también [5] => junto a esto [6] => del mismo modo [7] => a su vez [8] => de hecho [9] => igualmente [10] => inclusive ) ) 
LOc0

Pues no entiendo. Estoy probando con esto:

$todos_los_sinonimos=array('sin embargo' => array('además', 'por otro lado', 'así mismo'), 'mas' => array('pero', 'empero', 'si bien', 'no obstante'), 'empero' => array ( 'pero', 'mas', 'no obstante', 'sin embargo'), 'pero' => array('por contra', 'al contrario', 'en cambio'));

$a='te lo digo [sin embargo] yo emperonete estoy aquí sin embargo yo te lo digo veces sin embargo mas je je je';

y todas las salidas son:

[tonikelope@eniac_arch64 ~]$ php lol.php 

string(161) "te lo digo [sin embargo] yo emperonete estoy aquí <b>{sin embargo}[así mismo]</b> yo te lo digo veces <b>{sin embargo}[además]</b> <b>{mas}[pero]</b> je je je"
[tonikelope@eniac_arch64 ~]$ php lol.php 

string(167) "te lo digo [sin embargo] yo emperonete estoy aquí <b>{sin embargo}[por otro lado]</b> yo te lo digo veces <b>{sin embargo}[además]</b> <b>{mas}[si bien]</b> je je je"
[tonikelope@eniac_arch64 ~]$ php lol.php 

string(172) "te lo digo [sin embargo] yo emperonete estoy aquí <b>{sin embargo}[por otro lado]</b> yo te lo digo veces <b>{sin embargo}[por otro lado]</b> <b>{mas}[empero]</b> je je je"
[tonikelope@eniac_arch64 ~]$ php lol.php 

string(167) "te lo digo [sin embargo] yo emperonete estoy aquí <b>{sin embargo}[además]</b> yo te lo digo veces <b>{sin embargo}[por otro lado]</b> <b>{mas}[si bien]</b> je je je"
[tonikelope@eniac_arch64 ~]$ php lol.php 

string(166) "te lo digo [sin embargo] yo emperonete estoy aquí <b>{sin embargo}[así mismo]</b> yo te lo digo veces <b>{sin embargo}[así mismo]</b> <b>{mas}[empero]</b> je je je"
[tonikelope@eniac_arch64 ~]$ php lol.php 

string(166) "te lo digo [sin embargo] yo emperonete estoy aquí <b>{sin embargo}[así mismo]</b> yo te lo digo veces <b>{sin embargo}[así mismo]</b> <b>{mas}[empero]</b> je je je"
[tonikelope@eniac_arch64 ~]$ php lol.php 

string(166) "te lo digo [sin embargo] yo emperonete estoy aquí <b>{sin embargo}[por otro lado]</b> yo te lo digo veces <b>{sin embargo}[además]</b> <b>{mas}[empero]</b> je je je"
[tonikelope@eniac_arch64 ~]$ 

¿Estás usando el último código que puse? Es que hice cambios que apenas se nota...

En cada vuelta del bucle preg_replace_callback busca una palabra que no esté entre llaves, corchetes o dentro de otra y la cambia. Luego sigue leyendo y si la vuelve a encontrar hace el cambio.

Al terminar la vuelta, coge la siguiente palabra del array de sinónimos y empieza a buscar por el principio de la cadena.

Y así hasta el final. La cosa es que da igual que haya sinónimos que apunten a otros de forma "circular" porque pasa de todo lo que esté entre corchetes y llaves.

Salu2 ;)

PD: ponme el array entero pero en vez de usar var_dump() usa var_export()

M

Tienes razón, ahora si que funciona, yo usaba este código

	
foreach($todos_los_sinonimos as $palabra => $sinonimos)
	{
	$a=preg_replace_callback('/(?<![{\[a-zñ])'.$palabra.'(?![}\]a-zñ])/i', create_function('$p', 'global $sinonimos; return count($sinonimos)>1?"{<b><font color=green>".$p[0]."</font></b>} [<b><font color=#FF0000>".$sinonimos[mt_rand(0, count($sinonimos)-1)]."</font></b>]":$p[0];'), $a);
	}

Se ve que se vuelve loco con los colores, habrá que dejarlo en negro :(

Muchas gracias, ahora a cenarr :D

1
LOc0

Me alegro. Para los colores usa mejor:

<span style="color: green;"><b>hola</b></span>

Salu2 ;)

M

Lo de los corchetes todavía no ha quedado

por ejemplo, yo he puesto:


$a='te [lo digo sin embargo yo emperonete estoy aquí sin embargo yo te lo digo veces sin embargo] mas je je je';

Debería respetar todo lo que hay dentro, pero no lo hace ¿sabrías cuál es la expresión regular correcta? he probado varias y no me funcionan.

LOc0

La expresión regular está pensada para evitar palabras o expresiones de hasta dos palabras dentro de corchetes. Para más de dos palabras hay que darle otra vuelta de tuerca. Como soy un perfeccionista aburrido, WAIT...

LOc0
eureka?

Salu2 ;)

M

Hola, pues parece que sigue sin respetar los corchetes, puede ser que lo haga con dos o tres palabras pero debería hacerlo con todo. Yo obtengo este resultado:

te lo [hola sin embargo tal y cual digo {sin embargo}[además] yo estoy emperonete aquí {sin embargo}[asimismo] yo te lo digo veces {sin embargo}[por otro lado] mas je] je je

LOc0
$todos_los_sinonimos=array('sin embargo' => array('pero'), 'pero' => array('no obstante', 'sin embargo', 'aún así'));

$a='te lo [hola sin embargo tal y cual digo sin embargo yo estoy emperonete aquí sin embargo yo te lo digo veces sin embargo mas je je ] je pero no creo';

foreach($todos_los_sinonimos as $palabra => $sinonimos)
	$a=preg_replace_callback('/([\[{][^\]}]*?)?(?<![a-zñ])'.$palabra.'(?![a-zñ])(.*?[\]}])?/i', create_function('$p', 'global $sinonimos; return (!isset($p[1]) && !isset($p[2]) && count($sinonimos)>0)?"<b>{".$p[0]."}[".$sinonimos[mt_rand(0, count($sinonimos)-1)]."]</b>":$p[0];'), $a);
   
var_dump($a);

Las regex a veces hacen más cosas de las que se "supone". Pruébalo así que yo creo que es la definitiva.

Salu2 ;)

M

AHORA ESTÁ PERFECTO! VERY GOOD!! :D

Tengo un código que me he currado para detectar verbos en diferentes formas y conjugaciones y reemplazarlos también. Como no soy programador creo que se podía haber ahorrado muuuucho código y hacerlo de mejor forma ¿quieres que te lo envíe?

LOc0

Me alegro y no, no me aburro tanto xDDD (si tienes dudas postea que por aquí siempre hay algún gurú deambulando).

Salu2 ;)

M

Oye, estoy intentando añadir una opción para excepciones, es decir, palabras que no deben ser reemplazadas y que las toma de un archivo txt.

He modificado el código de esta manera:

        //// EXCEPCIONES, PALABRAS QUE NO SE REEMPLAZAN
		$todo   = file_get_contents ("conectorexcept.txt");
		$excepciones   = preg_split("/[\r\n]+/",$todo);//ARRAY DE PALABRAS QUE NO DEBEN SER REEMPLAZADAS
		
	//SI COINCIDE CON ALGUNA EXCEPCIÓN
	$comprobacion= $todos_los_sinonimos[strtolower(trim($registro['palabra']))];
	$excepcion =  in_array($comprobacion[0], $excepciones);
if ($excepcion==false)
			{
 foreach($todos_los_sinonimos as $palabra => $sinonimos)
                 $a=preg_replace_callback('/([\[{][^\]}]*?)?(?<![a-zñ])'.$palabra.'(?![a-zñ])(.*?[\]}])?/i', create_function('$p', 'global $sinonimos; return (!isset($p[1]) && !isset($p[2]) && count($sinonimos)>0)?"<span style=color:green;><b>{".$p[0]."}</span> <span style=color:red;>[".$sinonimos[mt_rand(0, count($sinonimos)-1)]."]</b></span>":$p[0];'), $a);

}

Pero no funciona, ¿sabes donde tengo el fallo?

LOc0

$excepciones=array_unique(array_map(create_function('$a', 'return trim(strtolower($a));'), file('conectorexcept.txt', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES)));

foreach($todos_los_sinonimos as $palabra => $sinonimos)
{
         if(!in_array($palabra, $excepciones))
         {
     $a=preg_replace_callback('/([\[{][^\]}]*?)?(?<![a-zñ])'.$palabra.'(?![a-zñ])(.*?[\]}])?/i', create_function('$p', 'global $sinonimos; return (!isset($p[1]) && !isset($p[2]) && count($sinonimos)>0)?"<span style=color:green;><b>{".$p[0]."}</span> <span style=color:red;>[".$sinonimos[mt_rand(0, count($sinonimos)-1)]."]</b></span>":$p[0];'), $a); 
        }
}

Y me tengo que pirar que tengo trabajo acumulado.

Salu2 ;)