Ayuda con StringRegExpReplace

Pregunta Sin Miedo no te cortes cualquier cosa para empezar - Autoit se comienza facilmente.Para Ordenes o Comandos sueltos. Ver nota como preguntar.
avechuche
Hacker del Foro
Mensajes: 188
Registrado: 13 Ago 2009, 09:53

Ayuda con StringRegExpReplace

Mensaje por avechuche »

Bueno resulta que estoy haciendo un programa y necesito usar esta herramienta, el tema seria asi

Quiero insertar parentesis cada vez que encuentre un texto como por ejemplo "p^q" (pueden ser otros), pero solo si no tiene parentesis. Osea que si encuentra "p^q", agregue los parentesis pero si antes de "p" no hay "(" y después de la "q" no hay ")". Me esta volviendo loco esa funcion de au3, tiene mil cosas que no se por donde arrancar ... Gracias!
Avatar de Usuario
Ximorro
Profesional del Autoit
Mensajes: 1500
Registrado: 10 Jul 2009, 12:35
Ubicación: Castellón, España

Re: Ayuda con StringRegExpReplace

Mensaje por Ximorro »

Parece que estás estudiando expresiones lógicas ;-)
No soy muy experto en esto de las expresiones regulares pero creo que he llegado a una solución. Es cosa de decirle que coja p^q pero que antes de la p no haya paréntesis abierto y después de la q no haya paréntesis cerrado:

$cadena = "p | p^q | (p^q) ^ !q"
$res = StringRegExpReplace($cadena, "[^(]p\^q[^)]", "(p^q)")
ConsoleWrite($res & @CRLF)


"^" hay que escaparlo porque fuera de corchetes significa "inicio de línea".
"¿Y no será que en este mundo hay cada vez más gente y menos personas?". Mafalda (Quino)
avechuche
Hacker del Foro
Mensajes: 188
Registrado: 13 Ago 2009, 09:53

Re: Ayuda con StringRegExpReplace

Mensaje por avechuche »

Ximorro escribió:Parece que estás estudiando expresiones lógicas ;-)
No soy muy experto en esto de las expresiones regulares pero creo que he llegado a una solución. Es cosa de decirle que coja p^q pero que antes de la p no haya paréntesis abierto y después de la q no haya paréntesis cerrado:

$cadena = "p | p^q | (p^q) ^ !q"
$res = StringRegExpReplace($cadena, "[^(]p\^q[^)]", "(p^q)")
ConsoleWrite($res & @CRLF)


"^" hay que escaparlo porque fuera de corchetes significa "inicio de línea".

Estudiando no es nada, tengo que hacer un programa que me las resuelva y explicar el codigo ^^, Dando un resultado logico y una expresion equivalente. El programa ya casi esta, lo que tengo que perfeccionar algunas cosas para achicar el code.
Vamos a ver que pasa con esta solucion! Muchas gracias!

PD: Casi, pero no anda osea anda en ciertos casos, por ejemplo si tengo "pvp^qv(p^q)^q" me devuelve "p(p^q)(p^q)^q", me esta robando 2 "v"
Avatar de Usuario
Ximorro
Profesional del Autoit
Mensajes: 1500
Registrado: 10 Jul 2009, 12:35
Ubicación: Castellón, España

Re: Ayuda con StringRegExpReplace

Mensaje por Ximorro »

Anda estás por aquí :smt006

Uau, pues si la cosa es publicable cuando acabes nos la pones en el foro, tiene pinta de ser una pasada. ¿Entonces simplifica expresiones lógicas? ¿comprueba equivalencias?

Estaba pensando en lo de que p o q pueden ser cualquier letra. Creo que también lo he solucionado:
$cadena = "p | p^z | (a^d) ^ !q"
$res = StringRegExpReplace($cadena, "[^(]([[:alpha:]]\^[[:alpha:]])[^)]", "(${1})")
ConsoleWrite($res & @CRLF)


Cambio las letras concretas por [[:alpha:]] para que acepte cualquiera. Englobo "letra^letra" entre paréntesis para hacer un grupo, que puedo referenciar luego con ${1} en la sustitución para añadirle los paréntesis, así mantiene las letras originales.
Lo que no se cómo diablos se podría hacer lo contrario: quitar los paréntesis, porque añadir cosas al grupo es fácil pero quitarlas...
"¿Y no será que en este mundo hay cada vez más gente y menos personas?". Mafalda (Quino)
avechuche
Hacker del Foro
Mensajes: 188
Registrado: 13 Ago 2009, 09:53

Re: Ayuda con StringRegExpReplace

Mensaje por avechuche »

Ximorro escribió:Anda estás por aquí :smt006

Uau, pues si la cosa es publicable cuando acabes nos la pones en el foro, tiene pinta de ser una pasada. ¿Entonces simplifica expresiones lógicas? ¿comprueba equivalencias?

Estaba pensando en lo de que p o q pueden ser cualquier letra. Creo que también lo he solucionado:
$cadena = "p | p^z | (a^d) ^ !q"
$res = StringRegExpReplace($cadena, "[^(]([[:alpha:]]\^[[:alpha:]])[^)]", "(${1})")
ConsoleWrite($res & @CRLF)


Cambio las letras concretas por [[:alpha:]] para que acepte cualquiera. Englobo "letra^letra" entre paréntesis para hacer un grupo, que puedo referenciar luego con ${1} en la sustitución para añadirle los paréntesis, así mantiene las letras originales.
Lo que no se cómo diablos se podría hacer lo contrario: quitar los paréntesis, porque añadir cosas al grupo es fácil pero quitarlas...
Vamos a probar con eso, quitar no es nada, solo busco "(p^q)" y segun que valor de verdad tome cada proposicion es el resultado, por ejemplo si p = 1 y q = 1, entonces todo eso "(p^q)" es 1, se van todos los parentesis. Eso es solo para el resultado logico, las equivalencias solo las hago aplicando las propiedades (DeMorgan, Distributiva, etc)
Avatar de Usuario
Ximorro
Profesional del Autoit
Mensajes: 1500
Registrado: 10 Jul 2009, 12:35
Ubicación: Castellón, España

Re: Ayuda con StringRegExpReplace

Mensaje por Ximorro »

Uf, había un errorcillo (¡no había visto tu postdata!, ¿la has añadido después?), esto es más difícil de lo que parece. Ya te digo que no soy un experto así que lo que te ponga tú testéalo bien con diferentes cadenas para asegurarse de que hace lo que quieres.
El caso es que los "not paréntesis", o sea, [^(] y el otro, igualmente se asocian a caracteres de la cadena original (siempre que no sean paréntesis, que es lo que queremos, pero igual se asocian).

Eso quiere decir que a la hora de hacer la sustitución la cadena asociada es por ejemplo " p^z " (fíjate que hay espacios), con lo que sustituye eso con "(p^z)", que sí, añade los paréntesis, pero quita los espacios.
Es más grave si no hay espacios, por ejemplo "p|p^z|(a^q)^!q" (no tiene espacios) queda como "p(p^z)(a^q)^!q", pues la cadena encontrada es "|p^z"|, que sustituye con "(p^z)".

Bueno, pero es solucionable, lo que he hecho es tomar también en grupos esos caracteres antes y después del p^q, o equivalente con otras letras, para mantenerlos en la sustitución, sería esto:
$res = StringRegExpReplace($cadena, "([^(])([[:alpha:]]\^[[:alpha:]])([^)])", "${1}(${2})${3}")
¡Casi nada! Pero ahora funciona perfectamente, si no salen más problemas ;-)

Por cierto, que ahora que me he dado cuenta de eso sí es fácil lo de quitar paréntesis, de hecho es más fácil:
$res = StringRegExpReplace($cadena, "\(([[:alpha:]]\^[[:alpha:]])\)", "${1}") ;Ojo, esto es para quitar paréntesis, no es lo que quieres, no vayamos a liarla :smt005
"¿Y no será que en este mundo hay cada vez más gente y menos personas?". Mafalda (Quino)
avechuche
Hacker del Foro
Mensajes: 188
Registrado: 13 Ago 2009, 09:53

Re: Ayuda con StringRegExpReplace

Mensaje por avechuche »

Ya casi esta ^^, falta nada :)

Código: Seleccionar todo

$cadena = "p^p^zv(a^d)^q"
$res = StringRegExpReplace($cadena, "([^(])([[:alpha:]]\^[[:alpha:]])([^)])", "${1}(${2})${3}")
ConsoleWrite($res & @CRLF)
Ese code me devuelve "p^(p^z)v(a^d)^q", pero en realidad me tendria que devolver "(p^p)^zv(a^d)^q". Solo puedo lograr el segundo resultado (el válido) si a la cadena original le agrego un espacio en blanco al principio.

Código: Seleccionar todo

$cadena = " p^p^zv(a^d)^q"
Siguiendo con lo de la cadena original, si esta fuese asi "p^p^zva^d^q", no pone los parentesis ni al principio ni al final, solo se soluciona si tienen un espacio en blanco. Quedando asi para que ande perfectamente.

Código: Seleccionar todo

$cadena = " p^p^zv(a^d)^q "
Avatar de Usuario
Ximorro
Profesional del Autoit
Mensajes: 1500
Registrado: 10 Jul 2009, 12:35
Ubicación: Castellón, España

Re: Ayuda con StringRegExpReplace

Mensaje por Ximorro »

¿Qué más te da (p^p)^z o p^(p^z) , si AND es una operación asociativa?
Es broma :smt003

Buenoooo, pues se me ocurre que antes de la expresión haya "cualquier cosa que no sea paréntesis abierto O el inicio de la cadena", y lo mismo para el final, porque por ejemplo ""avp^q" también fallará...

Eso se haría así:
$res = StringRegExpReplace($cadena, "([^(]|^)([[:alpha:]]\^[[:alpha:]])([^)]|$)", "${1}(${2})${3}")

Espero que ya esté porque cada vez se está embrollando más y estoy llegando al límite, como te digo no soy un experto en estas cosas...

Espero que usar una "v" como OR no te dé problemas, piensa que realmente es una letra y puede ser asociada a [[:alpha:]]. No creo que haya problemas porque combinaciones v^ o ^v son errores, al haber dos operadores seguidos. Pero si quisieras hacer lo de los paréntesis para OR no tengo claro que funcionara bien...

Por cierto, [:alpha:] toma todas las letras, si siempre usas minúsculas puedes usar [:lower:], así igual es más rápido al comprobar menos caracteres.
"¿Y no será que en este mundo hay cada vez más gente y menos personas?". Mafalda (Quino)
avechuche
Hacker del Foro
Mensajes: 188
Registrado: 13 Ago 2009, 09:53

Re: Ayuda con StringRegExpReplace

Mensaje por avechuche »

Código: Seleccionar todo

$res = StringRegExpReplace($cadena, "([^(]|^)([[:alpha:]]\^[[:alpha:]])([^)]|$)", "${1}(${2})${3}")
Eso anda perfecto, todavia no le encontre error ^^ ... Si vos llegaste al limite que queda para mi que yo no entiendo casi nada de esta funcion, si tenes ganas y time expliquela, osea hay partes que las entiendo
Por ejemplo si separamos en terminos con respecto a ")(" quedaria asi

Código: Seleccionar todo

1) ([^(]|^)
2) ([[:alpha:]]\^[[:alpha:]])
3) ([^)]|$)
1) Entiendo solo esta parte "[^(]" que seria que coinicia con cualquier caracter menos con "(". La parte "|^", no se que es ¿?
2) Esta es facil, si supiera como trabaja la funcion diria que busca el caracter "^" y se fija si antes y despues de este hay un caracter, respetando el primer puntos "1)", que no alla parentesis antes y despues de "[:alpha:]"
3) Lo mismo que la "1), pero lo que no entiendo es "|$"

Esta parte "${1}(${2})${3}", ni cerca ^^ ... Imagino algo, pero no se como explicarlo (se dice que si no se sabe explicar es porque no se entiendió) puede ser si, pero mas o menos ^^ ...

Bueno ahora mientras escribo, probando, encontre otro "error" que creo que seria mas facil de resolver

Tengo esto

Código: Seleccionar todo

$Cadena = "0<0<0<0<0>0v0^0v0^0^(0v0)"
$cadena = StringRegExpReplace($cadena, "([^(]|^)([[:alnum:]]\^[[:alnum:]])([^)]|$)", "${1}(${2})${3}")
Me devuelve esto:

Código: Seleccionar todo

0<0<0<0<0>0v(0^0)v0^0^(0v0)
Cuando tendria que devolver esto:

Código: Seleccionar todo

0<0<0<0<0>0v(0^0)v(0^0)^(0v0)
Esto ultimo se soluciona si vuelvo a llamar a la funcion StringRegExpReplace, pero tendria que reemplazar todo de una.


Otro ejemplo. Tengo

Código: Seleccionar todo

$cadena = "0<0<0<0<0>0v0^0v0^0^(0v0)"
$cadena = StringRegExpReplace($cadena, "([^(]|^)([[:alnum:]]<[[:alnum:]])([^)]|$)", "${1}(${2})${3}")
$cadena = StringRegExpReplace($cadena, "([^(]|^)([[:alnum:]]\^[[:alnum:]])([^)]|$)", "${1}(${2})${3}")
Me devuelte

Código: Seleccionar todo

(0<0)<0<(0<0)>0v(0^0)v0^0^(0v0)
Cuando tendria que devolver

Código: Seleccionar todo

(0<0)<(0<0)<0>0v(0^0)v(0^0)^(0v0)
Avatar de Usuario
Ximorro
Profesional del Autoit
Mensajes: 1500
Registrado: 10 Jul 2009, 12:35
Ubicación: Castellón, España

Re: Ayuda con StringRegExpReplace

Mensaje por Ximorro »

Te lo voy a explicar pero por favor mírate también la ayuda de StringRegExp, que al fin y al cabo es lo que yo he usado.
Te explico cómo he ido haciendo yo, de "dentro a fuera". Primero queremos que mire "p^q", pero leo que "^" fuera de corchetes significa inicio de cadena, con lo que hay que "escaparlo" como carácter especial. El escape es "\".
Así que empezamos con "p\^q".
Como queremos que en vez de p o q tome cualquier letra, sustituimos eso por [[:alpha:]], pero en la explicación voy a seguir con p y q para que se vea mejor la expresión...
Queremos que no tenga paréntesis, de ahí el [^(] antes de p^q y el [^)] de después. Hay que tener en cuenta que dentro de corchetes ^ significa NOT, no es lo mismo que fuera, que era "inicio de cadena".

Precisamente lo que queda es para marcar eso, que la expresión esté al principio o al final de la cadena. Ahí fallaba porque le digo que empiece por cualquier cosa que no sea un paréntesis, pero si está al principio de cadena no empieza por cualquier cosa, ¡empieza por NADA!.
Para eso uso el carácter "|", que aquí es un OR. Como he comentado antes el carácter "^" fuera de corchetes significa inicio de cadena, que junto con el OR tenemos que
"[^(]|^"
significa: un carácter cualquiera que no sea paréntesis abierto O el inicio de la cadena.

Planteamiento similar para "[^)]|$", donde como habrás imaginado, "$" significa "fin de cadena"

Ahora los grupos :smt003
En las expresiones regulares agrupas subexpresiones con paréntesis. Resulta que esas expresiones agrupadas, los grupos, las guarda y las puedes referenciar después en StringRegExpReplace.
Si te fijas he hecho tres grupos:
(no paréntesis abierto O inicio de cadena)(letra^letra)(no paréntesis cerrado O fin cadena)
A la hora de hacer la sustitución cada grupo recibe un número según el orden en que están (empezando en 1), se referencian con dólar "$", así $2 es el segundo grupo, el "p^q".
Así que si sustituyo lo que encuentra por ${1}(${2})${3} pondrá el carácter que hay antes del p^q o nada si es inicio de cadena, después el p^q rodeado de paréntesis, y al final el carácter que haya después o fin de cadena.

¿Es esta la mejor manera? No lo sé, quizás haya alguna más compacta o más efectiva, yo la he sacado a base de parchearla según los problemas que nos íbamos encontrando...

Esta es la explicación de la expresioncita. Ahora miro los otros problemas que han salido a ver si se puede hacer algo, pero te agradecería que no me dejaras solo ante el peligro, haz tus experimentos a ver si sacamos algo...
"¿Y no será que en este mundo hay cada vez más gente y menos personas?". Mafalda (Quino)
Avatar de Usuario
Ximorro
Profesional del Autoit
Mensajes: 1500
Registrado: 10 Jul 2009, 12:35
Ubicación: Castellón, España

Re: Ayuda con StringRegExpReplace

Mensaje por Ximorro »

Respecto al primer problema, buuuuf qué complicado es esto de las expresiones regulares. Se puede hacer maravillas pero hay que controlar...
Bien, veo que el problema general es que por ejemplo en expresiones tipo "p^q^r^s^t^u" devuelve "(p^q)^r^(s^t)^u"

¿Por qué? Pues porque primero ha encontrado "[inicio cadena]p^q^", que sustituye por "[inicio cadena](p^q)^".
Ahora le queda por mirar "r^s^t^u", pero realmente antes de "r" no hay un inicio de cadena, pues es una subcadena, pero tampoco usa el "^" anterior como "carácter distinto de abrir paréntesis" porque ese carácter ya ha sido consumido en el anterior emparejamiento. Con lo que realmente la siguiente subexpresión que sí empareja con el patrón es "s^t", por eso pone eso entre paréntesis y se ha saltado "r^s".

¡Un dolor de cabeza!

Lo he solucionado usando otra estrategia, pero no sé si se romperá en otros casos... Ahora en vez de mirar inicio o fin de cadena miro si hay un carácter distinto de paréntesis o nada (sí se puede mirar "nada" después de todo, con el carácter de repetición "?" que significa "se repite una o ninguna vez".

Así esta expresión:

$res = StringRegExpReplace($cadena, "([^(])?([[:alpha:]]\^[[:alpha:]])([^)]?)", "${1}(${2})${3}")

ya devuelve (p^q)^(r^s)^(t^u).
O "0<0<0<0<0>0v(0^0)v(0^0)^(0v0)" si usas [:alnum:].

Con un cambio idéntico en la expresión del "menor que" sí obtengo:
(0<0)<(0<0)<0>0v(0^0)v(0^0)^(0v0)

Que por cierto, si te fijas esos dos StringRegExpReplace se pueden poner de forma muy compacta en uno sólo, pues se hace exactamente la misma sustitución, y las expresiones sólo se diferencian en que en el centro o tienen un "^" o un "<". Así que las dos son equivalentes a poner eso con un OR:
$cadena = "0<0<0<0<0>0v0^0v0^0^(0v0)"
$res = StringRegExpReplace($cadena, "([^(])?([[:alnum:]](\^|<)[[:alnum:]])([^)])?", "${1}(${2})${3}")
ConsoleWrite($res & @CRLF) ; Devuelve (0<0)<(0<0)<0>0v(0^0)^(0^0)^(0v0)
"¿Y no será que en este mundo hay cada vez más gente y menos personas?". Mafalda (Quino)
Avatar de Usuario
Ximorro
Profesional del Autoit
Mensajes: 1500
Registrado: 10 Jul 2009, 12:35
Ubicación: Castellón, España

Re: Ayuda con StringRegExpReplace

Mensaje por Ximorro »

Error, ¡y horror!
Ahora resulta que éste último método sin mirar inicio y fin de cadena no funciona si ya hay paréntesis...
"p | p^z | (a^q) ^ !q" se queda como "p | (p^z) | ((a^q)) ^ !q"

Pues a mí no se me ocurre ya cómo hacer una expresión que agrupe todos los parches... :smt010

Dado el carácter asociativo te puede servir hacerlo en dos partes, vaya, a lo cutre, pero esto con las pruebas que he hecho sí funciona. Se trata de quitar primero los paréntesis que ya haya en esas expresiones, y luego ponerlos (pero como no hay esta vez es fácil ponerlos).
$res = StringRegExpReplace($cadena, "\(([[:alpha:]]\^[[:alpha:]])\)", "${1}") ;Quitar paréntesis
$res = StringRegExpReplace($res, "([[:alpha:]]\^[[:alpha:]])", "(${1})") ;Poner paréntesis


Así creo que funciona bien, lo que pasa es que si ya hay paréntesis y varios operadores "^" seguidos puede que la expresión resultante tenga los paréntesis cambiados, pero es equivalente dada las asociatividad de AND, por ejemplo:
"p^q^r^t" pasa bien a "(p^q)^(r^t)"
"p^q^(r^t)" pasa a "(p^q)^(r^t)"
pero "p^(q^r)^t" también pasa a "(p^q)^(r^t)", que no ha respetado el paréntesis inicial pero puede pasar porque la expresión es equivalente ¿te sirve?

No me gusta tener que hacerlo en dos StringRegExpReplace, aunque si no encontramos otra solución...
"¿Y no será que en este mundo hay cada vez más gente y menos personas?". Mafalda (Quino)
Avatar de Usuario
Chefito
Profesional del Autoit
Mensajes: 2035
Registrado: 21 Feb 2008, 18:42
Ubicación: Albacete/Cuenca (España)

Re: Ayuda con StringRegExpReplace

Mensaje por Chefito »

Muy bueno Ximorro!!! Yo creo que me hubiese quedado atascado mucho antes :smt005 . Tampoco es que sea un experto en expresiones regulares.
Ximorro escribió:Dado el carácter asociativo te puede servir hacerlo en dos partes, vaya, a lo cutre, pero esto con las pruebas que he hecho sí funciona. Se trata de quitar primero los paréntesis que ya haya en esas expresiones, y luego ponerlos (pero como no hay esta vez es fácil ponerlos).$res = StringRegExpReplace($cadena, "\(([[:alpha:]]\^[[:alpha:]])\)", "${1}") ;Quitar paréntesis$res = StringRegExpReplace($res, "([[:alpha:]]\^[[:alpha:]])", "(${1})") ;Poner paréntesis
De cutre nada!!!. Es una muy buena idea :smt002 .
Ximorro escribió:pero "p^(q^r)^t" también pasa a "(p^q)^(r^t)", que no ha respetado el paréntesis inicial pero puede pasar porque la expresión es equivalente ¿te sirve?
Un muy pequeño defecto. La verdad, como tu bien has dicho, no se para que quiere meter eso entre paréntesis ya que no hace falta al ser asociativa. Si es para resolver operaciones algebraicas (lógicas, leyes de demorgan) no hace falta.

Si la cosa se pusiese tan dificil haciendolo con expresiones regulares, siempre se puede acudir a las funciones de tratamiento de strings. Un ejemplo de lo que quiere:

Código: Seleccionar todo

;para saber los rangos de códigos ascii:
;~ Chr(48) == "0", Chr(57) == "9", Chr(65) == "A", Chr(90) == "Z", Chr(97) == "a", Chr(122) = "z"
;~ $cadena="a^bc^d^e"
;~ $cadena = "a<b<c<d<0>evf^gvh^i^(jvk)"
;~ $cadena="p | p^z | (a^q) ^ !q"
;~ $cadena = "p^p^zv(a^d)^q"
$cadena="(a^b^(cde^f))"
;~ $cadena="p^(q^r)^t"
MsgBox(0,"",PonerParentesis($cadena))
Func PonerParentesis($texto)
	Local $pos=0
	While 1
		$pos=StringInStr($texto,"^",0,1,$pos+2)		;busco las posiciones de los caracteres ^. Sumo dos a $pos para buscar desde la 2º posición.
		If $pos Then	;si encuentra alguno, entra en la condición.
			$caracterPosMas1=Asc(StringMid($texto, $pos+1, 1))	;obtengo el caracter que hay delante del ^
			If ($caracterPosMas1>=48 And $caracterPosMas1<=57) Or ($caracterPosMas1>=65 And $caracterPosMas1<=90) Or ($caracterPosMas1>=97 And $caracterPosMas1<=122) Then	;si encuentra un caracter entre 0-9, a-z, A-Z se cumple la condición.
				$caracterPosMenos1=Asc(StringMid($texto, $pos-1, 1))	;obtengo el caracter que hay antes del ^
				If ($caracterPosMenos1>=48 And $caracterPosMenos1<=57) Or ($caracterPosMenos1>=65 And $caracterPosMenos1<=90) Or ($caracterPosMenos1>=97 And $caracterPosMenos1<=122) Then
					$caracterPosMas2=StringMid($texto, $pos+2, 1)	;obtengo el caracter que hay dos posiciones delante del ^
					$caracterPosMenos2=StringMid($texto, $pos-2, 1) ;obtengo el caracter que hay dos posiciones detrás del ^
					If $caracterPosMas2<>")" Or $caracterPosMenos2<>"(" Then	;si estos dos caracteres son los paréntesis (), entra en la condición
						;con lo siguiente, creo la nueva cadena con los paréntesis insertados en la subcadena de texto encontrada
						$texto=StringLeft($texto, $pos-2) & "(" & StringMid($texto, $pos-1,3) & ")" & StringRight($texto, StringLen($texto)-$pos-1)
						$pos+=3	;añado 3 posiciones más, los dos paréntesis que he insertado en la cadena, más el ^
					EndIf
				EndIf
			EndIf
		Else	;si stringinstr no encuentra ^ , sale del bucle
			ExitLoop
		EndIf
	WEnd
		Return $texto	;devuelvo la cadena resultante.
EndFunc
Ni que decir tiene que el de las dos expresiones regulares es mucho más rápido que este. Aunque no creo que se note a no ser que sean cadenas muy muy muy largas :smt003 . Logicamente no se puede comparar todas estas instrucciones con dos nativas del AutoIt en cuestión de velocidad (casi nunca :smt002 ).

Mmmmm....Avechuche, no me ha gustado mucho el que no hayas casi intervenido en el código. He visto que lo ha hecho todo Ximorro. La proxima vez intenta participar más aunque te equivoques. No pasa nada, para eso está el foro. Es una muy buena forma de aprender.

Saludos.
Cita vista en algún lugar de la red: En este mundo hay 10 tipos de personas, los que saben binario y los que no ;).
Avatar de Usuario
Ximorro
Profesional del Autoit
Mensajes: 1500
Registrado: 10 Jul 2009, 12:35
Ubicación: Castellón, España

Re: Ayuda con StringRegExpReplace

Mensaje por Ximorro »

Mare Chefito qué código, parece que no es fácil la cosa, hay que mirarlo con tranquilidad. Claro que el que tiene que mirarlo con tranquilidad y aprender es avechuche, que en efecto parece que me ha dejado sólo ante el peligro ;-)

Chefito, creo que puedes simplificar algo la búsqueda de rangos [A-Za-z0-9] usando las funciones StringIsAlpha y StringIsDigit, aunque sean para cadenas por supuesto se pueden usar en un único carácter.

El programita de Chefito va fino, fino. Pero ayer hice avances con lo de expresiones regulares así que aquí va, es que tienta lo de hacer esto en una sólo línea ¿verdad? :smt003

Primero una puntualización: las llaves en el patrón de sustitución son opcionales, sólo hay que usarlas si estás mezclando números de grupo con números que quieres poner literalmente, así que en nuestro caso en vez de poner "${1}(${2})${3}" se puede poner "$1($2)$3", que queda más claro.

Ahora el avance. Resulta que en la ayuda de AutoIt para StringRegExp pone un enlace a una descripción aún más detallada que lo que pone ahí. Si creía que era complejo, aún es más.

Pues en esa descripción, que por cierto está aquí:
http://www.autoitscript.com/autoit3/pcrepattern.html

En el apartado "Lookahead assertions" podemos ver que se pueden hacer emparejamientos sin que una parte del mismo forme parte del grupo, por ejemplo "\w+(?=;)" es una palabra seguida de un ";", pero el ";" no queda incluido en el emparejamiento, con lo que puede ser usado en el siguiente.

Si en vez de "?=" usamos "?!" es lo contrario, "que no esté", por ejemplo pone que "foo(?!bar)" son las palabras "foo" que NO están seguidas por "bar".
Así que para que nuestra subexpresión p^q NO esté seguida por paréntesis de cierre ponemos al final "(?!\))"

Para el principio es parecido, está explicado en "Lookbehind assertions". Se concluye que para que NO empiece por paréntesis abierto hay que poner "(?<!\()" ¡menudo churro!

Estas "aserciones", tal como las llaman, no forman grupos, así que ahora tenemos sólo el grupo $1 que es nuestro p^q. Lo bueno es que esas aserciones se comprueban sin "consumir" los caracteres, con lo que se pueden reutilizar en la siguiente comprobación, así que las concatenaciones de operadores ya están solucionados.
Con estos cambios la expresión queda:
$res = StringRegExpReplace($cadena, "(?<!\()([[:alpha:]]\^[[:alpha:]])(?!\))", "($1)")

Ahora:
"p^q^r^s^t" queda "(p^q)^(r^s)^t"
"p^(q^r)^s^t" queda "p^(q^r)^(s^t)" ¡mantiene el paréntesis que hemos forzado y encuentra el siguiente!
"p^q^(r^s)^t" queda "(p^q)^(r^s)^t", completando el que falta
"p^q^r^(s^t)" queda "(p^q)^r^(s^t)", pues al emparejar el primero no puede tomar el segundo para respetar el último ya puesto.

¿Se me escapa algo?

Bueno, sí, aún hay una cosita... como miramos que por ejemplo la expresión no empiece por paréntesis, si empieza no la toma... aunque no acabe. Así por ejemplo "(a^p^q^r^t^u)" la deja como "(a^(p^q)^(r^t)^u)", en vez de la más correcta "((a^p)^(q^r)^(t^u))" porque a^p no la acepta pues empieza por paréntesis, aunque no acabe.
Por lo mismo "(a^p^r)" la deja igual porque "a^p" empieza por paréntesis y p^r tiene al final el de cierre, con lo que no cuadra con nuestra expresión.

Quitando esto creo que los problemas anteriores están solucionados.

Por cierto, que el código "currado a mano" de Chefito funciona perfectamente en esos casos.
Ahora estoy mirando una cosa que pone después en la ayuda de Aserciones múltiples y patrones condicionales, creo que podría mirarse a la vez que empiece y acabe por paréntesis, con lo que se solucionaría este último problema.
"¿Y no será que en este mundo hay cada vez más gente y menos personas?". Mafalda (Quino)
avechuche
Hacker del Foro
Mensajes: 188
Registrado: 13 Ago 2009, 09:53

Re: Ayuda con StringRegExpReplace

Mensaje por avechuche »

Muchas gracias por la ayuda, hasta ahora todo perfecto.

Ya se que la conjuncion es asociativa, pero eso lo puse como ejemplo, el tema es asi. Yo necesito un programa que resuelva una operacion logica, devolviendo un resultado logico y una expresion equivalente a la original, por eso necesito incorporar los parentesis, por ejemplo

$Cadena = "pvq^r". Eso no tiene ninguna ciencia, se resuelve el "^" y luego el "v", pero si quiero hacer una exprasion equivalente a esa, aplicaria distributiva, pero como lo hago?, poniendo los parentesis, por ejemplo asi

$Cadena ="(pvq)^r

Teniendo eso, aplico la distributiva quedandome (r^p)v(r^q), con eso logro lo que quiero, un resultado logico, en este caso "1 1 1 1 1 0 0 0 - Contingencia" y una expresion equivalente "(r^p)v(r^q)"

Con respecto a lo que no hice nada, si hice, lo que pasa es que yo no se como funciona, tengo que leer muy pero muy a fondo esta funcion de au3
Avatar de Usuario
Ximorro
Profesional del Autoit
Mensajes: 1500
Registrado: 10 Jul 2009, 12:35
Ubicación: Castellón, España

Re: Ayuda con StringRegExpReplace

Mensaje por Ximorro »

Una curiosidad ¿qué es el operador "<" en tus expresiones? Por ejemplo cuando hiciste "0<0<0<0<0>0v0^0v0^0^0v0" ¿Es un operador booleano?

Creo que al fin tengo la solución con expresiones regulares. Es usando patrones condicionales, básicamente lo último que tenía pero haciendo que mire el paréntesis de cierre sólo si existe el de apertura.
Resulta que en la ayuda hay un ejemplo que es casi lo que queremos, porque casualmente lo que hace es buscar expresiones con paréntesis opcionales, anda que si llego a verlo antes...

El caso es que finalmente, salvo catástrofe, con esto creo que funciona perfectamente, al menos igual que la función de Chefito en todas las expresiones que he probado:
$res = StringRegExpReplace($cadena, "(\()?([[:alpha:]]\^[[:alpha:]])(?(1)\))", "($2)")

Dentro del patrón, ese "?(1)" comprueba el primer grupo, que es "(\()?", o sea, si hay paréntesis o no. Si hay paréntesis ese subpatrón condicional "(?(1)\))" mira entonces si hay paréntesis de cierre.

En la sustitución ahora hay que usar el segundo grupo, porque "(\()?" SÍ hace grupo, a diferencia de la "Lookbehind assertion" de antes, que no formaba.

Pues esto es lo que hay, y hasta ahí llego.

Comprendo que si nunca has usado este tipo de cosas te supere, a mí desde luego ya me duele la cabeza. De hecho no creo que haya expertos reales en expresiones regulares más que los que lo han programado, porque vaya tela :smt005 pero bueno, mirando la ayuda de AutoIt para StringRegExp ya se pueden hacer bastantes cosas muy potentes. Cuando la cosa se complica pues o profundizas, a riesgo de acabar con tu cordura, o haces una rutina que se lo curre tipo lo que ha hecho Chefito.

Si puede leer inglés es interesante ampliar lo de la ayuda AutoIt es esa página
http://www.autoitscript.com/autoit3/pcrepattern.html
que de hecho como puedes ver es de la propia web de AutoIT, pero no está en la ayuda offline. Sin eso yo no habría completado este problema ni de coña...

Pues nada, publicarás tu analizador/"resolvedor" de expresiones booleanas ¿no?
¿Hace simplificaciones tipo p^¬p = 0 y cosas de esas?
"¿Y no será que en este mundo hay cada vez más gente y menos personas?". Mafalda (Quino)
Avatar de Usuario
Chefito
Profesional del Autoit
Mensajes: 2035
Registrado: 21 Feb 2008, 18:42
Ubicación: Albacete/Cuenca (España)

Re: Ayuda con StringRegExpReplace

Mensaje por Chefito »

Ximorro escribió:$res = StringRegExpReplace($cadena, "(\()?([[:alpha:]]\^[[:alpha:]])(?(1)\))", "($2)")
Y mirándola parece que no es tanto eeehhh? Te cagas! :smt005 . Menudo estudio has tenido que hacer Ximorro :smt003 . Yo no creo que hubiese tenido tanta paciencia y me hubiese ido por la vía de programar la función (si fuese para mí, puede que sí lo hubiese intentado). Igualmente no se si podría haber llegado a la solución. A las expresiones regulares complicadas les tengo grima :smt005 .

Solamente decir que: MUY BIEN XIMORRO!!! Eres una máquina :smt002 . Encima, al final se te ha quedado bastante compacta. Buena currada de investigación y programación :smt024 .
Ximorro escribió:Si puede leer inglés es interesante ampliar lo de la ayuda AutoIt es esa páginahttp://www.autoitscript.com/autoit3/pcrepattern.html
Muy interesante. Algún día le tendré que dedicar algo de tiempo.
Hay que pensar que ejemplos y explicaciones de expresiones regulares tienes que tener los que quieras en la red, ya que este lenguaje las ha heredado de c o c++. Otra cosa es querer romperse la cabeza y, como tu bien dices, arriesgarse a volverse loco con esto :smt005 .
Según Wikipedia:
PCRE: biblioteca de ExReg para C, C++ y otros lenguajes que puedan utilizar bibliotecas dll (Visual Basic 6 por ejemplo).
Fíjate lo que dice,y yo tanto tiempo programando en vb6 y creo que nunca utilicé expresiones regulares :smt005 .
Ximorro escribió:Chefito, creo que puedes simplificar algo la búsqueda de rangos [A-Za-z0-9] usando las funciones StringIsAlpha y StringIsDigit, aunque sean para cadenas por supuesto se pueden usar en un único carácter.
Tienes razón. La costumbre de hacerlo así por vb6 :smt002 . Además, es este caso se solucionaría con StringIsAlNum. Aunque la solución sea la tuya, lo pongo corregido para que lo vea la gente:

Código: Seleccionar todo

;~ $cadena="a^bc^d^e"
;~ $cadena = "a<b<c<d<0>evf^gvh^i^(jvk)"
;~ $cadena="p | p^z | (a^q) ^ !q"
$cadena = "p^p^zv(a^d)^q"
;~ $cadena="(a^b^(cde^f))"
;~ $cadena="p^(q^r)^t"
MsgBox(0,"",PonerParentesis($cadena))
Func PonerParentesis($texto)
	Local $pos=0
	While 1
		$pos=StringInStr($texto,"^",0,1,$pos+2)		;busco las posiciones de los caracteres ^. Sumo dos a $pos para buscar desde la 2º posición.
		If $pos Then	;si encuentra alguno, entra en la condición.
			$caracterPosMas1=StringMid($texto, $pos+1, 1)	;obtengo el caracter que hay delante del ^
			If StringIsAlNum($caracterPosMas1) Then	;si encuentra un caracter entre 0-9, a-z, A-Z se cumple la condición.
				$caracterPosMenos1=StringMid($texto, $pos-1, 1)	;obtengo el caracter que hay antes del ^
				If StringIsAlNum($caracterPosMenos1) Then
					$caracterPosMas2=StringMid($texto, $pos+2, 1)	;obtengo el caracter que hay dos posiciones delante del ^
					$caracterPosMenos2=StringMid($texto, $pos-2, 1) ;obtengo el caracter que hay dos posiciones detrás del ^
					If $caracterPosMas2<>")" Or $caracterPosMenos2<>"(" Then	;si estos dos caracteres son los paréntesis (), entra en la condición
						;con lo siguiente, creo la nueva cadena con los paréntesis insertados en la subcadena de texto encontrada
						$texto=StringLeft($texto, $pos-2) & "(" & StringMid($texto, $pos-1,3) & ")" & StringRight($texto, StringLen($texto)-$pos-1)
						$pos+=3	;añado 3 posiciones más, los dos paréntesis que he insertado en la cadena, más el ^
					EndIf
				EndIf
			EndIf
		Else	;si stringinstr no encuentra ^ , sale del bucle
			ExitLoop
		EndIf
	WEnd
		Return $texto	;devuelvo la cadena resultante.
EndFunc
Bueno, yo creo que el tema ya lo has solucionado Ximorro. Al final te has vuelto un experto en expresiones regulares :smt005 :smt005 .

Saludos.
Cita vista en algún lugar de la red: En este mundo hay 10 tipos de personas, los que saben binario y los que no ;).
avechuche
Hacker del Foro
Mensajes: 188
Registrado: 13 Ago 2009, 09:53

Re: Ayuda con StringRegExpReplace

Mensaje por avechuche »

Ximorro escribió:Una curiosidad ¿qué es el operador "<" en tus expresiones? Por ejemplo cuando hiciste "0<0<0<0<0>0v0^0v0^0^0v0" ¿Es un operador booleano?

Creo que al fin tengo la solución con expresiones regulares. Es usando patrones condicionales, básicamente lo último que tenía pero haciendo que mire el paréntesis de cierre sólo si existe el de apertura.
Resulta que en la ayuda hay un ejemplo que es casi lo que queremos, porque casualmente lo que hace es buscar expresiones con paréntesis opcionales, anda que si llego a verlo antes...

El caso es que finalmente, salvo catástrofe, con esto creo que funciona perfectamente, al menos igual que la función de Chefito en todas las expresiones que he probado:
$res = StringRegExpReplace($cadena, "(\()?([[:alpha:]]\^[[:alpha:]])(?(1)\))", "($2)")

Dentro del patrón, ese "?(1)" comprueba el primer grupo, que es "(\()?", o sea, si hay paréntesis o no. Si hay paréntesis ese subpatrón condicional "(?(1)\))" mira entonces si hay paréntesis de cierre.

En la sustitución ahora hay que usar el segundo grupo, porque "(\()?" SÍ hace grupo, a diferencia de la "Lookbehind assertion" de antes, que no formaba.

Pues esto es lo que hay, y hasta ahí llego.

Comprendo que si nunca has usado este tipo de cosas te supere, a mí desde luego ya me duele la cabeza. De hecho no creo que haya expertos reales en expresiones regulares más que los que lo han programado, porque vaya tela :smt005 pero bueno, mirando la ayuda de AutoIt para StringRegExp ya se pueden hacer bastantes cosas muy potentes. Cuando la cosa se complica pues o profundizas, a riesgo de acabar con tu cordura, o haces una rutina que se lo curre tipo lo que ha hecho Chefito.

Si puede leer inglés es interesante ampliar lo de la ayuda AutoIt es esa página
http://www.autoitscript.com/autoit3/pcrepattern.html
que de hecho como puedes ver es de la propia web de AutoIT, pero no está en la ayuda offline. Sin eso yo no habría completado este problema ni de coña...

Pues nada, publicarás tu analizador/"resolvedor" de expresiones booleanas ¿no?
¿Hace simplificaciones tipo p^¬p = 0 y cosas de esas?


El operador "<" es "Si solo si" y ">" es "Entonces"

Claro que hace estas reducciones "p^¬p = 0" es por eso que necesito los parentesis (para algunos casos) para reducir la funcion. En cuando lo tenga terminado lo posteo. Ya hace rato que estoy con esto, arranco, dejo, arranco, dejo. :) Muchas gracias!!!!
avechuche
Hacker del Foro
Mensajes: 188
Registrado: 13 Ago 2009, 09:53

Re: Ayuda con StringRegExpReplace

Mensaje por avechuche »

Encontre otro "error" que no es error, pero seria ya irse de mambo, el code de Chefito si bien es practicamente igual al que tenia (Yo uso un For) me gusta mas porq es mas simple.
Avatar de Usuario
Ximorro
Profesional del Autoit
Mensajes: 1500
Registrado: 10 Jul 2009, 12:35
Ubicación: Castellón, España

Re: Ayuda con StringRegExpReplace

Mensaje por Ximorro »

Bueno, de experto nada, es que me tocaba los huevs que no salía y me encabezoné :smt003

Por cierto avechuche, has puesto esto en el foro de "Preguntas sencillas" ¿¿y mira la que has armado?? :smt005

Usa el código que te parezca mejor, pero no hace falta que te diga cuál usaría yo, ¡todo eso en una línea! ;-)

Y un momento, ¿dices que el código de Chefito es parecido al que tenías? ¡¿Tenías un código y no nos lo has puesto para que tengamos algo con lo que empezar?! :smt018

Creo que luego haré pruebas de velocidad, no es relevante porque se va a usar en cadenas pequeñas pero por curiosidad, para saber si las expresiones regulares son más rápidas que el código desarrollado. Supongo que sí más que nada porque el procesamiento de la expresión regular corre en C compilado...

¿UN ERROR? Bueno creo que yo ya paro y más si no vas a usar la expresión regular pero dinos qué es, tengo curiosidad en saber en qué falla...

Estoy ansioso de ver el programa, tiene pinta de ser muy interesante, y más para los que estén estudiando estas cosas.
Además con esa idea se podrían hacer otras cosas, a lo mejor algo parecido para simplificar expresiones aritméticas o algo así.
"¿Y no será que en este mundo hay cada vez más gente y menos personas?". Mafalda (Quino)
Responder