Los predicados de comparación son muy útiles cuando queremos buscar columnas que cumplen con alguna condición, como hemos visto aquí:
https://firebird21.wordpress.com/2014/04/27/los-predicados-de-comparacion/
De todos ellos, el más poderoso es SIMILAR TO.
Pero justamente por ser el más poderoso es también el más complicado para entenderlo y para obtener de él el máximo provecho.
Caracteres especiales
Cuando usamos SIMILAR TO hay algunos caracteres que tienen un significado especial, y son los siguientes:
[ ] ( ) | ^ – + * % _ ? { }
y también el carácter de escape, si el carácter de escape fue definido.
Caracteres comunes
Si no hay caracteres especiales ni carácter de escape entonces SIMILAR TO funciona igual que el operador «=»
'NAPOLEON' SIMILAR TO 'NAPOLEON' -- Verdadero
'NAPOLEON BONAPARTE' SIMILAR TO 'NAPOLEON' -- Falso
'NAPOLEON' SIMILAR TO 'NAPOLEON BONAPARTE' -- Falso
'NAPOLEON' SIMILAR TO 'Napoleón' -- Puede ser, depende del COLLATE utilizado
Comodines
Se puede usar el comodín _ que reemplaza a un carácter cualquiera, y el comodín % que reemplaza a cualquier cantidad de caracteres.
'NAPOLEON' SIMILAR TO 'N_POLEON' -- Verdadero
'NAPOLEON' SIMILAR TO 'N_LEON' -- Falso
'NAPOLEON' SIMILAR TO 'N%LEON' -- Verdadero
'NAPOLEON' SIMILAR TO 'NAPO%LEON%' -- Verdadero
'NAPOLEON' SIMILAR TO 'NAPOOO%LEON' -- Falso
'NAPOLEON' SIMILAR TO 'NAPOOO%LEON%' -- Falso
El primer caso es verdadero porque el segundo caracter podía ser cualquiera, incluyendo por supuesto a una A
El segundo caso es falso porque el guión bajo reemplaza a solamente un caracter y allí faltarían dos más
El tercer caso es verdadero porque el % reemplaza a cualquier cantidad de caracteres
El cuarto caso es verdadero porque el % también reemplaza al string vacío
El quinto caso es falso porque hay dos letras O sobrantes
El sexto caso es falso porque hay dos letras O sobrantes
Clases de caracteres
Un grupo de caracteres rodeados por corchetes se llama clase de caracteres. Hay coincidencia cuando un carácter, y solamente uno, de los que están rodeados por corchetes es igual.
'NAPOLEON' SIMILAR TO 'NAPO[LMN]EON' -- Verdadero
'NAPOLEON' SIMILAR TO 'NAPO[LE]ON' -- Falso
'NAPOLEON' SIMILAR TO 'NAPO[LMN][AEIOU]ON' -- Verdadero
El primer caso es verdadero porque la L se encuentra en la clase.
El segundo caso es falso porque solamente se puede usar un carácter de la clase y en este caso se necesitaría de dos.
El tercer caso es verdadero porque de la primera clase se extrae la L y de la segunda clase se extrae la E.
Rangos
Usar clases de caracteres es muy conveniente pero cuando los caracteres son muchos puede ser muy tedioso escribirlos a todos. Por eso se pueden usar rangos. Los rangos están compuestos por un carácter inicial, un guión, y un carácter final. Todos los caracteres que se encuentren entre ese carácter inicial y ese carácter final, ambos incluidos, estarán dentro de la clase.
'NAPOLEON' SIMILAR TO 'NAPO[J-R]EON' -- Verdadero
'NAPOLEON' SIMILAR TO 'NAPO[RSK-PXYZ]EON' -- Verdadero
'NAPOLEON' SIMILAR TO 'NAPO[AF-JM-SZ]EON' -- Falso
'NAPOLEON' SIMILAR TO 'NAPO[AF-JLM-SZ]EON' -- Verdadero
El primer caso es verdadero porque la L está entre las letras J y R.
El segundo caso es verdadero porque la L está entre las letras K y P.
El tercer caso es falso porque la L no está entre la F y la J, tampoco entre la M y la S, y tampoco se la ve en la clase
El cuarto caso es verdadero porque se ve a la L en la clase
Clases predefinidas
Hay algunas clases de caracteres que se utilizan muy frecuentemente entonces están predefinidas, para facilitarnos la vida. Son las siguientes:
[:ALPHA:]
Letras inglesas dentro de los rangos a .. z y A .. Z. Si se utiliza un COLLATE que sea CI entonces también incluye a las vocales acentuadas.
[:DIGIT:]
Los dígitos 0 .. 9
[:ALNUM:]
La unión de [:ALPHA:] con [:DIGIT:]
[:UPPER:]
Letras mayúsculas en el rango A .. Z. También coincide cuando las letras son minúsculas y el COLLATE es CI o es AI
[:LOWER:]
Letras minúsculas en el rango A .. Z. También coincide cuando las letras son mayúsculas y el COLLATE es CI o es AI
[:SPACE:]
El espacio en blanco (código ASCII 32)
[:WHITESPACE:]
Tabulador vertical (código ASCII 9), alimentador de línea (código ASCII 10), tabulador horizontal (código ASCII 11), alimentación de página (código ASCII 12), retorno del carro (código ASCII 13), y espacio en blanco (código ASCII 32).
Usar una clase predefinida es lo mismo que usar todos sus miembros. Las clases predefinidas pueden ser usadas solamente dentro de una definición de clases. Si necesitas verificar la coincidencia contra una clase predefinida y nada más, entonces debes usar dos pares de corchetes.
'NAPOLEON' SIMILAR TO 'NAPO[[:ALPHA:]]EON' -- Verdadero
'NAPOLEON' SIMILAR TO 'NAPO[[:DIGIT:]]EON' -- Falso
'NAPOLEON' SIMILAR TO 'NAPO[L[:DIGIT:]]EON' -- Verdadero
'NAPOLEON' SIMILAR TO '[[:ALPHA:]]' -- Falso
'N' SIMILAR TO '[[:ALPHA:]]' -- Verdadero
El primer caso es verdadero porque la letra L está incluida en la clase predefinida [:ALPHA:]
El segundo caso es falso porque la letra L no está incluida en la clase predefinida [:DIGIT:]
El tercer caso es verdadero porque la L está dentro de la clase
El cuarto caso es falso porque de la clase predefinida [:ALPHA:] solamente se puede usar una letra y NAPOLEON tiene 8 letras
El quinto caso es verdadero porque la letra N está incluida dentro de la clase predefinida [:ALPHA:]
Acento circunflejo
Si se usa un acento circunflejo ^ pueden darse dos casos:
- La clase empieza con un acento circunflejo. Siendo así todos los caracteres siguientes son excluidos de la clase
- La clase no empieza con un acento circunflejo. Siendo así la clase contiene todos los caracteres anteriores, excepto por los caracteres que se encuentren también después del acento circunflejo
'NAPOLEON' SIMILAR TO 'NAPO[^L]EON' -- Falso
'NAPOLEON' SIMILAR TO 'NAPO[^A-M]EON' -- Falso
'NAPOLEON' SIMILAR TO 'NAPO[^A-EL]EON' -- Falso
'NAPOLEON' SIMILAR TO 'NAPO[^[:DIGIT:]]LEON' -- Verdadero
'NAPOLEON' SIMILAR TO 'NAPO[A-M^R-V]EON' -- Verdadero
'NAPOLEON' SIMILAR TO 'NAPO[A-M^J-S]EON' -- Falso
'NAPOLEON' SIMILAR TO 'NAPO[A-M^L]EON' -- Falso
El primero caso es falso porque se excluye a la L
El segundo caso es falso porque se excluye a todos los caracteres que están en el rango A .. M
El tercer caso es falso porque se excluye a todos los caracteres que están en el rango A .. E y también a la L
El cuarto caso es verdadero porque se excluye solamente a los dígitos
El quinto caso es verdadero porque se incluye a todos los caracteres entre A .. M y se excluye a los que están entre R .. V, y la L se encuentra entre los incluidos
El sexto caso es falso porque la L se incluye en el rango A .. M pero se la excluye en el rango J .. S y la exclusión tiene preferencia
El séptimo caso es falso porque la L está en el rango A .. M pero específicamente se la excluye después
Cuantificadores
Los cuantificadores son los siguientes: ? * +
Además de números encerrados entre llaves
Y los usamos para indicar la cantidad de veces que queremos que se repitan los caracteres
El ? indica que el carácter o clase que le antecede debe ocurrir 0 ó 1 vez
'NAPOLEON' SIMILAR TO 'NAPO?LEON' -- Verdadero
'NAPOLEON' SIMILAR TO 'NAPOX?LEON' -- Verdadero
'NAPOLEON' SIMILAR TO 'NAPOXX?LEON' -- Falso
'NAPOLEON' SIMILAR TO 'NAPO[A-M]?EON' -- Verdadero
'NAPOLEON' SIMILAR TO 'N[A-E]?POLEON[R-Z]?' -- Verdadero
El primer caso es verdadero porque la letra O se encuentra 0 ó 1 vez
El segundo caso es verdadero porque la letra X se encuentra 0 ó 1 vez
El tercer caso es falso porque la letra X se encuentra 2 veces, y debería encontrarse 0 ó 1 vez para ser verdadero
El cuarto caso es verdadero porque la letra L se encuentra una vez en el rango A .. M
El quinto caso es verdadero porque la letra A se encuentra una vez en el rango A .. E y las letras R .. Z se encuentran 0 veces después de POLEON
El * indica que el carácter o clase que le antecede puede ocurrir 0, 1 ó muchas veces
'NAPOLEON' SIMILAR TO 'NAPO*LEON' -- Verdadero
'NAPOLEON' SIMILAR TO 'NAPOX*LEON' -- Verdadero
'NAPOLEON' SIMILAR TO 'NAPOXX*LEON' -- Falso
'NAPOLEON' SIMILAR TO 'NAPO[A-M]*EON' -- Verdadero
'NAPOLEON' SIMILAR TO 'N[A-E]*POLEON[R-Z]*' -- Verdadero
El primer caso es verdadero porque la letra O se encuentra 0, 1, ó más veces
El segundo caso es verdadero porque la letra X se encuentra 0, 1, ó más veces
El tercer caso es falso porque la letra X se encuentra 2 veces, y debería encontrarse 0 ó 1 vez para ser verdadero
El cuarto caso es verdadero porque la letra L se encuentra una vez en el rango A .. M
El quinto caso es verdadero porque la letra A se encuentra una vez en el rango A .. E y las letras R .. Z se encuentran 0 veces después de POLEON
El + indica que el carácter o clase que le antecede debe ocurrir 1 vez ó más de 1 vez. O sea que es obligatorio que ocurra.
'NAPOLEON' SIMILAR TO 'NAPO_+' -- Verdadero
'NAPOLEON' SIMILAR TO 'NAPO+LEON' -- Verdadero
'NAPOLEON' SIMILAR TO 'NAPOLEONX+' -- Falso
'NAPOLEON' SIMILAR TO 'NAPO[A-P]+EON' -- Verdadero
'NAPOLEON' SIMILAR TO 'NAPO[[:DIGIT:]]+EON' -- Falso
El primer caso es verdadero porque el carácter anterior al + puede ser cualquiera, y ocurrió una vez
El segundo caso es verdadero porque la letra O ocurrió una vez
El tercer caso es falso porque la letra X no ocurrió ni una vez
El cuarto caso es verdadero porque la letra L se encuentra en el rango A .. P y ocurrió una vez
El quinto caso es falso porque se necesitaba una letra L pero en su lugar hay dígitos
Si un carácter o una clase son seguidos por un número rodeado por llaves, ese carácter o esa clase deben repetirse exactamente ese número de veces
'NAPOLEON' SIMILAR TO 'NAPO{2}LEON' -- Falso
'NAPOLEON' SIMILAR TO 'NAPO{1}LEON' -- Verdadero
'NAPOLEON' SIMILAR TO 'NAP[[:ALPHA:]]{1}LEON' -- Verdadero
'NAPOLEON' SIMILAR TO 'NAP[[:ALPHA:]]{2}LEON' -- Falso
'NAPOLEON' SIMILAR TO 'NA[M-R]{2}LEON' -- Verdadero
El primer caso es falso porque la letra O debería estar 2 veces y está solamente 1 vez
El segundo caso es verdadero porque la letra O está 1 vez
El tercer caso es verdadero porque la letra O está incluida una vez en la clase predefinida [:ALPHA:]
El cuarto caso es falso porque la letra O está incluida una vez en la clase predefinida [:ALPHA:] y se está pidiendo que esté incluida dos veces
El quinto caso es verdadero porque la letra P está incluida una vez en el rango M .. R y la letra O está incluida una vez en ese rango, por lo tanto son 2
Si el número es seguido por una coma, entonces el carácter o la clase que le preceden deben repetirse al menos ese número de veces
'NAPOLEON' SIMILAR TO 'NAPO{1,}LEON' -- Verdadero
'NAPOLEON' SIMILAR TO 'NAPO{2,}LEON' -- Falso
'NAPOLEON' SIMILAR TO 'NA[E-S]{3,}' -- Verdadero
'NAPOLEON' SIMILAR TO 'NA[F-S]{3,}' -- Falso
El primer caso es verdadero porque la letra O se repite una vez o más
El segundo caso es falso porque la letra O no se repite dos veces o más
El tercer caso es verdadero porque los caracteres del rango E .. S se repiten 3 veces o más
El cuarto caso es falso porque la letra E no está en el rango
Si dentro de las llaves hay dos números separados por comas, siendo el segundo mayor o igual que el primero, entonces el carácter o la clase que le preceden deben repetirse al menos el primer número y como máximo, el segundo número
'NAPOLEON' SIMILAR TO 'NA[E-S]{2,3}' -- Falso
'NAPOLEON' SIMILAR TO 'NA[E-S]{2,6}' -- Verdadero
'NAPOLEON' SIMILAR TO 'NA[E-S]{4,6}' -- Verdadero
El primer caso es falso porque las letras E .. S se repiten 6 veces y deberían repetirse como máximo 3 veces
El segundo caso es verdadero porque las letras E .. S se repiten 6 veces, y deberían repetirse entre 2 y 6 veces
El tercer caso es verdadero porque las letras E .. S se repiten 6 veces y deberían repetirse entre 4 y 6 veces
La disyunción se realiza con el operador | y es verdadera cuando hay coincidencia con alguno de los dos ítems
'NAPOLEON' SIMILAR TO 'NAPO|LEON' -- Falso
'NAPOLEON' SIMILAR TO 'NAPOLEON|BONAPARTE' -- Verdadero
'NAPOLEON' SIMILAR TO 'MAR_+|NA_+|TUZ_+' -- Verdadero
El primer caso es falso porque NAPOLEON no es igual a NAPO y tampoco es igual a LEON
El segundo caso es verdadero porque NAPOLEON es igual a NAPOLEON
El tercer caso es verdadero porque NA_+ es verdadero
Subexpresiones
Puedes utilizar subexpresiones si las rodeas con paréntesis.
'NAPOLEON' SIMILAR TO 'NA(PA|PE|PI|PO|PU)LEON' -- Verdadero
'NAPOLEON' SIMILAR TO 'NA(P[M-R]+)LEON' -- Verdadero
'NAPOLEON' SIMILAR TO 'NA([M-R]{2})LEON' -- Verdadero
El primer caso es verdadero porque PO está incluido en la subexpresión
El segundo caso es verdadero porque PO está incluido en la subexpresión
El tercer caso es verdadero porque PO está incluido en la subexpresión
Caracteres especiales de escape
Para que la comparación pueda ser hecha contra un carácter que se usa dentro de los patrones de caracteres, ese carácter debe ser «escapado».
'NAPOLEON (FRANCIA)' SIMILAR TO 'N[^ ]+ \(F[^ ]+\)' ESCAPE '\' -- Verdadero
Este caso es verdadero porque se está verificando que empiece con N, que luego haya un espacio en blanco, un paréntesis abierto, una letra F, y un paréntesis cerrado.
Conclusión:
El predicado de comparación SIMILAR TO es el más poderoso de todos los predicados de comparación pero así también es el más difícil de entender y de usar completamente.
Sin embargo, bien que vale la pena el esfuerzo porque si dominas el uso de SIMILAR TO entonces tus comparaciones que involucren a strings serán muy rápidas, muy eficientes, y mucho más cortas de escribir que si debes hallar los mismos resultados sin usar SIMILAR TO.
Artículos relacionados:
Los predicados de comparación
El índice del blog Firebird21
El foro del blog Firebird21
Comentarios recientes