Reemplazar caracteres especiales en una columna con espacio

10

Estoy tratando de escribir una consulta que reemplaza los caracteres especiales con espacio. El siguiente código ayuda a identificar las filas. (los caracteres alfanuméricos, la coma y el espacio son válidos):

SELECT columnA
FROM tableA
WHERE columnA like '%[^a-Z0-9, ]%'

¿Cómo puedo integrar la función de reemplazo en la instrucción select para que todos los caracteres que no sean alfanuméricos, coma y espacio en el conjunto de resultados se reemplacen por '' (espacio). Este no funcionará:

SELECT replace(columnA,'%[^a-Z0-9, ]%',' ')
FROM tableA
WHERE columnA like '%[^a-Z0-9, ]%'
Stackoverflowuser
fuente

Respuestas:

11

Si tiene la garantía de que solo usará las 26 letras del alfabeto inglés de EE. UU. (Tanto en mayúsculas como en minúsculas), entonces puede evitar el uso LIKEy / o PATINDEXla notación de rango simple de [a-z](no necesita usar una "Z" mayúscula cuando se usa una intercalación que no distingue entre mayúsculas y minúsculas).

Sin embargo, si usted puede obtener caracteres que no se encuentran en el es-alfabeto todavía disponible en diferentes páginas de códigos / intercalaciones de VARCHARdatos (por ejemplo Þ= capital de América "espina" = SELECT CHAR(0xDE)), entonces puede que tenga que incluir los de la clase de caracteres: [a-z0-9, Þ]. Por supuesto, cuáles serían esos caracteres adicionales es por página de código.

Además, tenga en cuenta que tanto el tipo de clasificación (SQL Server frente a Windows) como la configuración de sensibilidad (mayúsculas y minúsculas, acento, etc., sensibles frente a insensibles) afectarán qué caracteres se incluyen en un rango particular. Por ejemplo, las intercalaciones de SQL Server clasifican las letras mayúsculas y minúsculas en el orden opuesto a las intercalaciones de Windows. Es decir, suponiendo una intercalación entre mayúsculas y minúsculas para ambos tipos de colaciones, una servirá AaBb...y la otra lo hará aAbB.... El efecto será que aestará dentro del rango de A-Zuno de ellos, pero no del otro. Y el rango de a-Zno coincidirá con ningún carácter en una intercalación binaria (uno que termine en uno _BINo _BIN2, pero no use _BIN) dado que el valor de Aes 65 yaes 97, por lo tanto, es un rango no válido de 97 a 65 ;-). Hay demasiadas variaciones para dar ejemplos aquí, así que intentaré publicar una explicación detallada en mi blog pronto (y luego actualizaré esto con el enlace). Sin embargo, si va a ser estricto acerca de aceptar solo caracteres en inglés de EE. UU. (Incluso si puede obtener letras válidas de otros idiomas), entonces su mejor opción probablemente será usar el siguiente patrón y clasificación:

LIKE '%[^A-Za-z0-9, ]%' COLLATE Latin1_General_100_BIN2

Ahora, si está respaldando NVARCHARdatos y puede obtener caracteres de "palabras" de varios idiomas, entonces T-SQL no será de mucha ayuda ya que no tiene una forma real de diferenciar estas cosas. En este caso, debe usar una Expresión regular (RegEx), específicamente el Replacemétodo / función, y estos solo están disponibles a través de SQLCLR. A continuación se muestra un ejemplo de reemplazo de varios caracteres "especiales", pero dejando todas las letras válidas en al menos un idioma:

DECLARE @Test NVARCHAR(500);
SET @Test = N'this$is%a<>TEST,;to}⌡↕strip╞╟╚══¶out_ç_ƒ▀ special-ij-೫-chars-舛-დ-א-B';
SELECT SQL#.RegEx_Replace4k(@Test, N'[\W\p{Pc}-[,]]', N' ', -1, 1, NULL); 

Devoluciones:

this is a  TEST, to   strip      out ç ƒ  special ij ೫ chars 舛 დ א B

La expresión RegEx significa:

  • \W= un "escape" RegEx que significa "cualquier carácter que no sea una palabra"
  • \p{Pc}= una "categoría" Unicode de "Puntuación, conector" (esto es necesario para la coincidencia solo porque esta "categoría" está específicamente excluida por el \Wescape)
  • -[,]= resta de clase (esto es necesario para excluir las comas de la coincidencia como "especiales" ya que están incluidas en el \Wescape)

Puede actualizar una tabla simplemente emitiendo:

UPDATE tbl
SET    tbl.field = SQL#.RegEx_Replace4k(tbl.field, N'[\W\p{Pc}-[,]]', N' ', -1, 1, NULL)
FROM   tbl
WHERE  SQL#.RegEx_IsMatch4k(tbl.field, N'[\W\p{Pc}-[,]]', 1, NULL) = 1;

Tenga en cuenta que para estos ejemplos, utilicé dos funciones disponibles en la biblioteca de la versión gratuita SQL # de funciones SQLCLR, que creé (pero de nuevo, estas son gratuitas). También tenga en cuenta que usé las versiones "4k", que son más rápidas debido al uso en NVARCHAR(4000)lugar de los NVARCHAR(MAX)tipos de parámetros. Si sus datos están utilizando NVARCHAR(MAX), simplemente elimine el "4k" de los nombres de las funciones.

Por favor vea también:

Solomon Rutzky
fuente
5

Tengo una publicación aquí que hace algo similar .

Básicamente estoy usando un CTE recursivo para recorrer una y otra vez reemplazando un carácter "malo" a la vez. Estoy usando STUFF para quitar 1 carácter (aunque puede usarlo para reemplazar con un espacio) y PATINDEX para encontrar la ubicación del personaje que quiero eliminar. Puede modificarlo ligeramente para hacer lo que está buscando. Sin embargo, crea una lista "buena", en realidad no actualiza la lista existente.

DECLARE @Pattern varchar(50) = '%[^A-Za-z0-9, ]%';

WITH FixBadChars AS (SELECT StringToFix, StringToFix AS FixedString, 1 AS MyCounter, Id
                FROM BadStringList
                UNION ALL
                SELECT StringToFix, Stuff(FixedString, PatIndex(@Pattern, 
                    FixedString COLLATE Latin1_General_BIN2), 1, ' ') AS FixedString, 
                    MyCounter + 1, Id
                FROM FixBadChars
                WHERE FixedString COLLATE Latin1_General_BIN2 LIKE @Pattern)
SELECT StringToFix, FixedString, MyCounter, Id
FROM FixBadChars
WHERE MyCounter = 
        (SELECT MAX(MyCounter) 
        FROM FixBadChars Fixed
        WHERE Fixed.Id = FixBadChars.Id)
OPTION (MAXRECURSION 1000);

Debería poder modificar la parte inferior para hacer una actualización en lugar de solo una consulta, pero en realidad no lo he intentado. Estoy bastante seguro de que se vería así:

UPDATE FixBadChars
SET StringToFix = FixedString
WHERE MyCounter = 
        (SELECT MAX(MyCounter) 
        FROM FixBadChars Fixed
        WHERE Fixed.Id = FixBadChars.Id)
OPTION (MAXRECURSION 1000);

En cuanto a la escalabilidad, devolví ~ 170k filas limpias en menos de 30 segundos. Una vez más, no estoy seguro de hacer una actualización, pero esto fue en mi computadora portátil, que es bastante lenta con solo 6 gb de ram.

Kenneth Fisher
fuente
0
Declare @String nchar(2000)='hg$%^AB,.:23ab-=+'

Declare @NewString VARCHAR(2000)=''
Declare @Lenght int=LEN(@String)
Declare @Index int=1

WHILE (@Index <= @Lenght)
BEGIN
    Declare @Letter nchar(1)=Substring(@String,@Index,1);
    Declare @ASCII int=ASCII(@Letter);
    If((@ASCII >= 48 and @ASCII <= 57) or (@ASCII >= 97 and @ASCII <= 122) or (@ASCII >= 65 and @ASCII <= 90))
    BEGIN
        SET @NewString += @Letter
    END
    ELSE
    BEGIN
        SET @NewString += ' '
    END
    SET @Index+=1

END
Select @NewString
William Mendoza
fuente