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:

  1. La clase empieza con un acento circunflejo. Siendo así todos los caracteres siguientes son excluidos de la clase
  2. 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

 

Anuncios