negacion de parte de una expresion regular

851 views
Skip to first unread message

Reverse Engineer

unread,
Mar 19, 2013, 7:19:45 PM3/19/13
to php...@googlegroups.com
Estoy extrayendo informacion de strings via expresiones regulares.
Se trata de parte de la informacion de medicamentos del tipo:
1- 45 mg comp.x 30         
2- gel x 20 g              
3- 500 mg caps.x 16
4- Chocolate env.x 237 ml  

de la cual se ha de extraer la parte de la dosis. El resultado esperado es:
1- 45 mg
2- nada (el x indica que es volumen, no dosis)
3- 500 mg
4- nada (el x indica que es volumen, no dosis)

En realidad los casos 2 y 4 no deberian dar resultado positivo y quedar excluidos del proceso.

Probando con un script php esta es la primera expresion pregmatch:
/([0-9]{1,4}\/?\.{0,1}[0-9]{0,3}).?(mg|ml|g|l|mcg|ui|mui|\%|u|u\/ml|g\%)/i

Los resultados obtenidos (separados en el array resultado de preg_match) son:
1- 45 mg
2- 20 g
3- 500 mg
4- 237 ml

los valores 2 y 4 no sirven como referencia asi que pense en negarlos con este patron:
/(?<!x\ )([0-9]{1,4}\/?\.{0,1}[0-9]{0,3}).?(mg|ml|g|l|mcg|ui|mui|\%|u|u\/ml|g\%)/i

O sea, simplemente agregando el (?<!x\ ) delante del patron original.
Obtengo resultados rarisimos:
1- 45 mg
2- 0 g (WTF)
3- 500 mg
4- 37 ml (WTF)

En el caso de los que deberian dar como resultado 'nada' o directamente no aparecer lo que pasa es que se 'comen' el primer caracter del indicador de dosis.

Any ideas?

Tordek

unread,
Mar 19, 2013, 8:22:46 PM3/19/13
to php...@googlegroups.com
2013/3/19 Reverse Engineer <llar...@gmail.com>:
> Estoy extrayendo informacion de strings via expresiones regulares.
> Se trata de parte de la informacion de medicamentos del tipo:
> 1- 45 mg comp.x 30
> 2- gel x 20 g
> 3- 500 mg caps.x 16
> 4- Chocolate env.x 237 ml
>
> de la cual se ha de extraer la parte de la dosis. El resultado esperado es:
> 1- 45 mg
> 2- nada (el x indica que es volumen, no dosis)
> 3- 500 mg
> 4- nada (el x indica que es volumen, no dosis)

1) Tirale "$string str_split($string, " x ");" y agarrá el primer
elemento, así descartás todo después de la x (asumiendo que podés
asegurar que la x no aparece en otros casos). Después matcheás la
regex sobre eso.

2) Hacé un parser de verdad (o lo mínimo necesario para obtener algo similar).

No todos los problemas se solucionan con regexen, y este es uno de esos.

Aside:
Si tu regex usa mucho un caracter como / podés usar otro delimitador
(@ y # son típicos) para ahorrarte escapes:

@([0-9]{1,4}/?\.{0,1}[0-9]{0,3}).?(mg|ml|g|l|mcg|ui|mui|%|u|u/ml|g%)@i

Con un par de simplificaciones ({0,3} == {,3}, {0,1} == ?, y dos
opcionales seguidos transformados en [\/\.]? (a menos que por algún
motivo puedas tener '34/.5') (y otras cosas que asumo y cambio un
poquito):

@(\d{1,4}([/\.]\d{1,3})?).?(mg|ml|g|l|mcg|ui|mui|%|u|u/ml|g%)@i

Otros factores a tomar en cuenta en el problema son: ¿qué tan
formateados son tus datos? Si te aparecen uno por línea, como tus
ejemplos, es mucho más fácil que si quisieras capturar varios matches
en un párrafo, por ejemplo.


> los valores 2 y 4 no sirven como referencia asi que pense en negarlos con
> este patron:
> /(?<!x\
> )([0-9]{1,4}\/?\.{0,1}[0-9]{0,3}).?(mg|ml|g|l|mcg|ui|mui|\%|u|u\/ml|g\%)/i
>
> O sea, simplemente agregando el (?<!x\ ) delante del patron original.
> Obtengo resultados rarisimos:
> 1- 45 mg
> 2- 0 g (WTF)

Lo que pasa con este es simple: "dame el número que no tenga una x
directamente antes", y te da el 0, porque en vez de x antes tiene un
2.

> 3- 500 mg
> 4- 37 ml (WTF)

Idem.
>
> En el caso de los que deberian dar como resultado 'nada' o directamente no
> aparecer lo que pasa es que se 'comen' el primer caracter del indicador de
> dosis.
>
> Any ideas?
>
> --
> Has recibido este mensaje porque estás suscrito al grupo "Grupo PHP
> Argentina" de Grupos de Google.
> Para anular la suscripción a este grupo y dejar de recibir sus correos
> electrónicos, envía un correo electrónico a
> php-arg+u...@googlegroups.com.
> Para publicar una entrada en este grupo, envía un correo electrónico a
> php...@googlegroups.com.
> Visita este grupo en http://groups.google.com/group/php-arg?hl=es.
> Para obtener más opciones, visita https://groups.google.com/groups/opt_out.
>
>

llarensj

unread,
Mar 20, 2013, 5:05:11 PM3/20/13
to php...@googlegroups.com
Eliminar las 'x ' por split, la sencillez misma, deberia haberseme ocurrido!
Gracias Tordek!

PD: El cardiologo excluyó los parsers de mi dieta ¬¬

llarensj

unread,
Mar 21, 2013, 11:40:28 AM3/21/13
to php...@googlegroups.com
La sencillez y efectividad del planteo de Tordek, me hizo reflexionar sobre mi propio planteo inicial: excesivamente complicado.
Reflexionando sobre las preguntas de tordek:
¿qué tan formateados son tus datos? 'casi previsiblemente'. Sucede que la informacion que pretendo extraer, ya ha sido 'extraida' y 'codificada' por una empresa, de una manera, tecnicamente hablando: PARA EL TUJES EN MUCHOS CASOS.
Si te aparecen uno por línea: si

Dentro de todas las variantes que tienen estas string, solo me interesan las que tienen la forma:
medidas_al_principio_de_la_string unidad_de_medida

Con esta simplificacion llegue a esta expresion regular:
#(^[0-9/\.]+)\ ?(mg|ml|g|l|mcg|ui|mui|\%|u|u/ml|g\%)#i

Me ha quedado en el tintero otro caso mas, pero extraerlo me deja con un resultado (supuestamente) inservible para la base de datos.
Una vez mas, gracias a Tordek por sus comentarios.

Tordek

unread,
Mar 21, 2013, 5:20:49 PM3/21/13
to php...@googlegroups.com
On 21/03/13 12:40, llarensj wrote:
> La sencillez y efectividad del planteo de Tordek, me hizo
> reflexionar sobre mi propio planteo inicial: excesivamente complicado.

A veces lo �nico que le falta al problema es un nuevo par de ojos :P

> PARA EL TUJES EN MUCHOS CASOS.

Como siempre.

> Con esta simplificacion llegue a esta expresion regular:
> #(^[0-9/\.]+)\ ?(mg|ml|g|l|mcg|ui|mui|\%|u|u/ml|g\%)#i

Excelente; conocer las fronteras del problema es uno de los pasos
m�s importantes.

Addendum:

Cuesti�n de estilo, yo har�a un par de cambios en la regex (pero
esto es todo personal:

'#^([0-9/\.]+) ?(mg|ml|g|l|mcg|ui|mui|%|u|u/ml|g%)#i'

Ni el espacio ni el % tienen significado especial, as� que no hace
falta escaparlos, y el ^ lo pongo afuera del par�ntesis porque no te
sirve de nada capturarlo en este caso.

(Y si bien podr�as cambiar (mg|ml|g|l) por (m?g|m?l) o (m?[gl]),
prefiero la versi�n expandida en este caso, porque es m�s clara.)

> Una vez mas, gracias a Tordek por sus comentarios.

De nada, cualquier cosa por los fans (?).


--
Guillermo O. �Tordek� Freschi. Programador, Escritor, Genio Maligno.
http://tordek.com.ar :: http://twitter.com/tordek
Reply all
Reply to author
Forward
0 new messages