¿Cómo quitar todos los caracteres no alfabéticos de la cadena en SQL Server?

Respuestas:

362

Prueba esta función:

Create Function [dbo].[RemoveNonAlphaCharacters](@Temp VarChar(1000))
Returns VarChar(1000)
AS
Begin

    Declare @KeepValues as varchar(50)
    Set @KeepValues = '%[^a-z]%'
    While PatIndex(@KeepValues, @Temp) > 0
        Set @Temp = Stuff(@Temp, PatIndex(@KeepValues, @Temp), 1, '')

    Return @Temp
End

Llámalo así:

Select dbo.RemoveNonAlphaCharacters('abc1234def5678ghi90jkl')

Una vez que comprenda el código, debería ver que es relativamente sencillo cambiarlo para eliminar también otros caracteres. Incluso podría hacer esto lo suficientemente dinámico como para pasar su patrón de búsqueda.

Espero eso ayude.

George Mastros
fuente
9
Este código elimina los caracteres no alfa (por lo que también se eliminan los números). Si desea dejar los números (eliminar caracteres no alfanuméricos), entonces ... reemplace ^ az con ^ az ^ 0-9 Esa cadena de búsqueda aparece en el código en dos lugares diferentes. Asegúrese de reemplazarlos a ambos.
George Mastros
26
Del comentario de Jeff: Creo que si quisiera quitar todas las letras y números que no sean, querría '^ a-z0-9' (versus '^ az ^ 0-9', que dejaría ^ en la cadena) .
Incluso Mien
1
+1 George. Este es uno de esos lugares donde el código "basado en conjuntos" y el uso de funciones escalares en línea tienen una gran dificultad para vencer fila por fila. Bien hecho. También he estado usando su función "Caps inicial", que tiene la misma forma básica, durante un par de años, ahora.
Jeff Moden
66
@Lynchie Cambiar '% [^ az]%' A '% [^ az]%' Básicamente, simplemente coloque un carácter de espacio después de la z.
George Mastros
8
El nombre de la variable KeepValues ​​es en realidad opuesto a lo que debe hacer. KeepValues ​​enumera los caracteres que deben excluirse ..
nee21
167

Versión parametrizada de la increíble respuesta de G Mastros :

CREATE FUNCTION [dbo].[fn_StripCharacters]
(
    @String NVARCHAR(MAX), 
    @MatchExpression VARCHAR(255)
)
RETURNS NVARCHAR(MAX)
AS
BEGIN
    SET @MatchExpression =  '%['+@MatchExpression+']%'

    WHILE PatIndex(@MatchExpression, @String) > 0
        SET @String = Stuff(@String, PatIndex(@MatchExpression, @String), 1, '')

    RETURN @String

END

Solo alfabético:

SELECT dbo.fn_StripCharacters('a1!s2@d3#f4$', '^a-z')

Solo numérico:

SELECT dbo.fn_StripCharacters('a1!s2@d3#f4$', '^0-9')

Alfanumérico solamente:

SELECT dbo.fn_StripCharacters('a1!s2@d3#f4$', '^a-z0-9')

No alfanumérico:

SELECT dbo.fn_StripCharacters('a1!s2@d3#f4$', 'a-z0-9')
Incluso Mien
fuente
3
¡Prefiero esta versión y creé mi adaptación de la respuesta de G Mastros antes de desplazarme hacia abajo para votar!
Earnshavian
El patrón regex no parece funcionar con todos los espacios en blanco. Si deseo eliminar todos los caracteres especiales, excepto los caracteres alfanuméricos y los espacios en blanco, espero usar el SELECT dbo.fn_StripCharacters('a1!s2 spaces @d3# f4$', '^a-z0-9\s')que todavía elimina los espacios en blanco. También intenté usar, [[:blank:]]pero eso rompe la función y no se elimina nada de la cadena. Lo más cercano que he conseguido es mediante el uso de: SELECT dbo.fn_StripCharacters('a1!s2 spaces @d3# f4$', '^a-z0-9 ')(codificar un espacio en el patrón de expresiones regulares). Sin embargo, eso no elimina los saltos de línea.
Billy McKee
2
@BillyMcKee Agregue el espacio al principio en lugar de agregarlo al final de la expresión regular. SELECT dbo.fn_StripCharacters('a1!s2 spaces @d3# f4$', '^ a-z0-9')
Mike
8

Lo creas o no, en mi sistema esta función fea funciona mejor que la elegante de G Mastros.

CREATE FUNCTION dbo.RemoveSpecialChar (@s VARCHAR(256)) 
RETURNS VARCHAR(256) 
WITH SCHEMABINDING
    BEGIN
        IF @s IS NULL
            RETURN NULL
        DECLARE @s2 VARCHAR(256) = '',
                @l INT = LEN(@s),
                @p INT = 1

        WHILE @p <= @l
            BEGIN
                DECLARE @c INT
                SET @c = ASCII(SUBSTRING(@s, @p, 1))
                IF @c BETWEEN 48 AND 57
                   OR  @c BETWEEN 65 AND 90
                   OR  @c BETWEEN 97 AND 122
                    SET @s2 = @s2 + CHAR(@c)
                SET @p = @p + 1
            END

        IF LEN(@s2) = 0
            RETURN NULL

        RETURN @s2
J Brune
fuente
¿Qué pasa con comas, puntos, espacios, etc.?
sojim
cuánto difiere si no usa un ASCIIentero aquí y compara directamente la salida de SUBSTRINGalgunos caracteres, por ejemplo: SET @ch=SUBSTRING(@s, @p, 1)yIF @ch BETWEEN '0' AND '9' OR @ch BETWEEN 'a' AND 'z' OR @ch BETWEEN 'A' AND 'Z' ...
S.Serpooshan
Agregue WITH SCHEMABINDING a su función como lo ha hecho su función. Estás usando VARCHAR, su función está usando NVARCHAR. Si los parámetros que está pasando a su función son VARCHAR, debe usar VARCHAR en lugar de NVARCHAR dentro de su función, de lo contrario, su sistema necesitará convertir los valores de cadena de VARCHAR a NVARCHAR antes de que pueda realizar la función que es más costosa. Incluso con esos cambios, su función aún podría ser más rápida, pero esos son algunos ejemplos que puedo ver donde su función podría funcionar más lentamente en su situación.
EricI
1
Su función también está usando NVARCHAR (MAX) y su función está usando VARCHAR (256). Si 256 es todo lo que necesita, cambie su función para usar VARCHAR (256) también y su función funcionará más rápido para usted.
EricI
5

Sabía que SQL era malo en la manipulación de cadenas, pero no pensé que sería tan difícil. Aquí hay una función simple para eliminar todos los números de una cadena. Habría mejores formas de hacer esto, pero este es un comienzo.

CREATE FUNCTION dbo.AlphaOnly (
    @String varchar(100)
)
RETURNS varchar(100)
AS BEGIN
  RETURN (
    REPLACE(
      REPLACE(
        REPLACE(
          REPLACE(
            REPLACE(
              REPLACE(
                REPLACE(
                  REPLACE(
                    REPLACE(
                      REPLACE(
                        @String,
                      '9', ''),
                    '8', ''),
                  '7', ''),
                '6', ''),
              '5', ''),
            '4', ''),
          '3', ''),
        '2', ''),
      '1', ''),
    '0', '')
  )
END
GO

-- ==================
DECLARE @t TABLE (
    ColID       int,
    ColString   varchar(50)
)

INSERT INTO @t VALUES (1, 'abc1234567890')

SELECT ColID, ColString, dbo.AlphaOnly(ColString)
FROM @t

Salida

ColID ColString
----- ------------- ---
    1 abc1234567890 abc

Ronda 2 - Lista negra basada en datos

-- ============================================
-- Create a table of blacklist characters
-- ============================================
IF EXISTS (SELECT * FROM sys.tables WHERE [object_id] = OBJECT_ID('dbo.CharacterBlacklist'))
  DROP TABLE dbo.CharacterBlacklist
GO
CREATE TABLE dbo.CharacterBlacklist (
    CharID              int         IDENTITY,
    DisallowedCharacter nchar(1)    NOT NULL
)
GO
INSERT INTO dbo.CharacterBlacklist (DisallowedCharacter) VALUES (N'0')
INSERT INTO dbo.CharacterBlacklist (DisallowedCharacter) VALUES (N'1')
INSERT INTO dbo.CharacterBlacklist (DisallowedCharacter) VALUES (N'2')
INSERT INTO dbo.CharacterBlacklist (DisallowedCharacter) VALUES (N'3')
INSERT INTO dbo.CharacterBlacklist (DisallowedCharacter) VALUES (N'4')
INSERT INTO dbo.CharacterBlacklist (DisallowedCharacter) VALUES (N'5')
INSERT INTO dbo.CharacterBlacklist (DisallowedCharacter) VALUES (N'6')
INSERT INTO dbo.CharacterBlacklist (DisallowedCharacter) VALUES (N'7')
INSERT INTO dbo.CharacterBlacklist (DisallowedCharacter) VALUES (N'8')
INSERT INTO dbo.CharacterBlacklist (DisallowedCharacter) VALUES (N'9')
GO

-- ====================================
IF EXISTS (SELECT * FROM sys.objects WHERE [object_id] = OBJECT_ID('dbo.StripBlacklistCharacters'))
  DROP FUNCTION dbo.StripBlacklistCharacters
GO
CREATE FUNCTION dbo.StripBlacklistCharacters (
    @String nvarchar(100)
)
RETURNS varchar(100)
AS BEGIN
  DECLARE @blacklistCt  int
  DECLARE @ct           int
  DECLARE @c            nchar(1)

  SELECT @blacklistCt = COUNT(*) FROM dbo.CharacterBlacklist

  SET @ct = 0
  WHILE @ct < @blacklistCt BEGIN
    SET @ct = @ct + 1

    SELECT @String = REPLACE(@String, DisallowedCharacter, N'')
    FROM dbo.CharacterBlacklist
    WHERE CharID = @ct
  END

  RETURN (@String)
END
GO

-- ====================================
DECLARE @s  nvarchar(24)
SET @s = N'abc1234def5678ghi90jkl'

SELECT
    @s                  AS OriginalString,
    dbo.StripBlacklistCharacters(@s)   AS ResultString

Salida

OriginalString           ResultString
------------------------ ------------
abc1234def5678ghi90jkl   abcdefghijkl

Mi desafío para los lectores: ¿Puedes hacer esto más eficiente? ¿Qué pasa con el uso de la recursividad?

Rob Garrison
fuente
probablemente podría escribir un mejor dbo.StripBlacklistCharacters () sin un bucle usando sommarskog.se/arrays-in-sql-2005.html#tblnum tabla de números unidos en su tabla de lista negra, pero hoy soy demasiado vago para intentarlo yo mismo ...
KM.
4

Si es como yo y no tiene acceso para agregar funciones a sus datos de producción, pero aún desea realizar este tipo de filtrado, aquí hay una solución SQL pura que utiliza una tabla PIVOT para volver a unir las piezas filtradas.

Nota : codifiqué la tabla con hasta 40 caracteres, tendrá que agregar más si tiene cadenas más largas para filtrar.

SET CONCAT_NULL_YIELDS_NULL OFF;

with 
    ToBeScrubbed
as (
    select 1 as id, '*SOME 222@ !@* #* BOGUS !@*&! DATA' as ColumnToScrub
),

Scrubbed as (
    select 
        P.Number as ValueOrder,
        isnull ( substring ( t.ColumnToScrub , number , 1 ) , '' ) as ScrubbedValue,
        t.id
    from
        ToBeScrubbed t
        left join master..spt_values P
            on P.number between 1 and len(t.ColumnToScrub)
            and type ='P'
    where
        PatIndex('%[^a-z]%', substring(t.ColumnToScrub,P.number,1) ) = 0
)

SELECT
    id, 
    [1]+ [2]+ [3]+ [4]+ [5]+ [6]+ [7]+ [8] +[9] +[10]
    +  [11]+ [12]+ [13]+ [14]+ [15]+ [16]+ [17]+ [18] +[19] +[20]
    +  [21]+ [22]+ [23]+ [24]+ [25]+ [26]+ [27]+ [28] +[29] +[30]
    +  [31]+ [32]+ [33]+ [34]+ [35]+ [36]+ [37]+ [38] +[39] +[40] as ScrubbedData
FROM (
    select 
        *
    from 
        Scrubbed
    ) 
    src
    PIVOT (
        MAX(ScrubbedValue) FOR ValueOrder IN (
        [1], [2], [3], [4], [5], [6], [7], [8], [9], [10],
        [11], [12], [13], [14], [15], [16], [17], [18], [19], [20],
        [21], [22], [23], [24], [25], [26], [27], [28], [29], [30],
        [31], [32], [33], [34], [35], [36], [37], [38], [39], [40]
        )
    ) pvt
Kyle Hale
fuente
Esta solución fue 2.3 veces más rápida para mí que usar una función en un conjunto de 235K filas. También tuve que hacer 2 reemplazos, y usé un total de cuatro CTE. Trabajó como un campeón.
JJS
4

Después de analizar todas las soluciones dadas, pensé que tenía que haber un método SQL puro que no requiriera una función o una consulta CTE / XML, y que no implique dificultades para mantener las instrucciones REPLACE anidadas. Aquí está mi solución:

SELECT 
  x
  ,CASE WHEN a NOT LIKE '%' + SUBSTRING(x, 1, 1) + '%' THEN '' ELSE SUBSTRING(x, 1, 1) END
    + CASE WHEN a NOT LIKE '%' + SUBSTRING(x, 2, 1) + '%' THEN '' ELSE SUBSTRING(x, 2, 1) END
    + CASE WHEN a NOT LIKE '%' + SUBSTRING(x, 3, 1) + '%' THEN '' ELSE SUBSTRING(x, 3, 1) END
    + CASE WHEN a NOT LIKE '%' + SUBSTRING(x, 4, 1) + '%' THEN '' ELSE SUBSTRING(x, 4, 1) END
    + CASE WHEN a NOT LIKE '%' + SUBSTRING(x, 5, 1) + '%' THEN '' ELSE SUBSTRING(x, 5, 1) END
    + CASE WHEN a NOT LIKE '%' + SUBSTRING(x, 6, 1) + '%' THEN '' ELSE SUBSTRING(x, 6, 1) END
-- Keep adding rows until you reach the column size 
    AS stripped_column
FROM (SELECT 
        column_to_strip AS x
        ,'ABCDEFGHIJKLMNOPQRSTUVWXYZ' AS a 
      FROM my_table) a

La ventaja de hacerlo de esta manera es que los caracteres válidos están contenidos en una cadena en la subconsulta, lo que facilita la reconfiguración para un conjunto diferente de caracteres.

La desventaja es que debe agregar una fila de SQL para cada carácter hasta el tamaño de su columna. Para facilitar esa tarea, solo utilicé el script de Powershell a continuación, este ejemplo si es para un VARCHAR (64):

1..64 | % {
  "    + CASE WHEN a NOT LIKE '%' + SUBSTRING(x, {0}, 1) + '%' THEN '' ELSE SUBSTRING(x, {0}, 1) END" -f $_
} | clip.exe
Dave Sexton
fuente
3
Incómodo en el caso general, pero fácil y útil para una consulta única con una columna estrecha.
Eric J.
3

Aquí hay otra forma de eliminar caracteres no alfabéticos usando un iTVF. Primero, necesita un divisor de cadena basado en patrones. Aquí hay uno tomado del artículo de Dwain Camp :

-- PatternSplitCM will split a string based on a pattern of the form 
-- supported by LIKE and PATINDEX 
-- 
-- Created by: Chris Morris 12-Oct-2012 
CREATE FUNCTION [dbo].[PatternSplitCM]
(
       @List                VARCHAR(8000) = NULL
       ,@Pattern            VARCHAR(50)
) RETURNS TABLE WITH SCHEMABINDING 
AS 

RETURN
    WITH numbers AS (
        SELECT TOP(ISNULL(DATALENGTH(@List), 0))
            n = ROW_NUMBER() OVER(ORDER BY (SELECT NULL))
        FROM
        (VALUES (0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) d (n),
        (VALUES (0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) e (n),
        (VALUES (0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) f (n),
        (VALUES (0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) g (n)
    )

    SELECT
        ItemNumber = ROW_NUMBER() OVER(ORDER BY MIN(n)),
        Item = SUBSTRING(@List,MIN(n),1+MAX(n)-MIN(n)),
        [Matched]
    FROM (
        SELECT n, y.[Matched], Grouper = n - ROW_NUMBER() OVER(ORDER BY y.[Matched],n)
        FROM numbers
        CROSS APPLY (
            SELECT [Matched] = CASE WHEN SUBSTRING(@List,n,1) LIKE @Pattern THEN 1 ELSE 0 END
        ) y
    ) d
    GROUP BY [Matched], Grouper

Ahora que tiene un divisor basado en patrones, debe dividir las cadenas que coinciden con el patrón:

[a-z]

y luego los concatena para obtener el resultado deseado:

SELECT *
FROM tbl t
CROSS APPLY(
    SELECT Item + ''
    FROM dbo.PatternSplitCM(t.str, '[a-z]')
    WHERE Matched = 1
    ORDER BY ItemNumber
    FOR XML PATH('')
) x (a)

MUESTRA

Resultado:

| Id |              str |              a |
|----|------------------|----------------|
|  1 |    testte d'abc |     testtedabc |
|  2 |            anr¤a |           anra |
|  3 |  gs-re-C“te d'ab |     gsreCtedab |
|  4 |         Mfe, DF |          MfeDF |
|  5 |           Rtemd |          Rtemd |
|  6 |          jadji |          jadji |
|  7 |      Cje y ret¢n |       Cjeyretn |
|  8 |        Jklbalu |        Jklbalu |
|  9 |       lene-iokd |       leneiokd |
| 10 |   liode-Pyrnie |    liodePyrnie |
| 11 |         Vs Gta |          VsGta |
| 12 |        Sƒo Paulo |        SoPaulo |
| 13 |  vAstra gAtaland | vAstragAtaland |
| 14 |  ¥uble / Bio-Bio |     ubleBioBio |
| 15 | Upln/ds VAsb-y |    UplndsVAsby |
Felix Pamittan
fuente
¿Hay alguna ventaja de usar esto sobre otras respuestas?
S.Serpooshan
2

Esta solución, inspirada en la solución del Sr. Allen, requiere una Numberstabla de enteros (que debe tener a mano si desea realizar operaciones de consulta serias con buen rendimiento). No requiere un CTE. Puede cambiar la NOT IN (...)expresión para excluir caracteres específicos, o cambiarla a una expresión IN (...)OR LIKEpara retener solo ciertos caracteres.

SELECT (
    SELECT  SUBSTRING([YourString], N, 1)
    FROM    dbo.Numbers
    WHERE   N > 0 AND N <= CONVERT(INT, LEN([YourString]))
        AND SUBSTRING([YourString], N, 1) NOT IN ('(',')',',','.')
    FOR XML PATH('')
) AS [YourStringTransformed]
FROM ...
Jay Bienvenu
fuente
Solución interesante a un problema no relacionado.
TaterJuice
2

Aquí hay una solución que no requiere crear una función o enumerar todas las instancias de caracteres para reemplazar. Utiliza una instrucción WITH recursiva en combinación con un PATINDEX para encontrar caracteres no deseados. Reemplazará todos los caracteres no deseados en una columna: hasta 100 caracteres incorrectos únicos contenidos en cualquier cadena dada. (Por ejemplo, "ABC123DEF234" contendría 4 caracteres incorrectos 1, 2, 3 y 4) El límite de 100 es el número máximo de recursiones permitidas en una instrucción WITH, pero esto no impone un límite en el número de filas para procesar, que solo está limitado por la memoria disponible.
Si no desea resultados DISTINCT, puede eliminar las dos opciones del código.

-- Create some test data:
SELECT * INTO #testData 
FROM (VALUES ('ABC DEF,K.l(p)'),('123H,J,234'),('ABCD EFG')) as t(TXT)

-- Actual query:
-- Remove non-alpha chars: '%[^A-Z]%'
-- Remove non-alphanumeric chars: '%[^A-Z0-9]%'
DECLARE @BadCharacterPattern VARCHAR(250) = '%[^A-Z]%';

WITH recurMain as (
    SELECT DISTINCT CAST(TXT AS VARCHAR(250)) AS TXT, PATINDEX(@BadCharacterPattern, TXT) AS BadCharIndex
    FROM #testData
    UNION ALL
    SELECT CAST(TXT AS VARCHAR(250)) AS TXT, PATINDEX(@BadCharacterPattern, TXT) AS BadCharIndex
    FROM (
        SELECT 
            CASE WHEN BadCharIndex > 0 
                THEN REPLACE(TXT, SUBSTRING(TXT, BadCharIndex, 1), '')
                ELSE TXT 
            END AS TXT
        FROM recurMain
        WHERE BadCharIndex > 0
    ) badCharFinder
)
SELECT DISTINCT TXT
FROM recurMain
WHERE BadCharIndex = 0;
Graeme Job
fuente
1

Puse esto en ambos lugares donde se llama PatIndex.

PatIndex('%[^A-Za-z0-9]%', @Temp)

para la función personalizada anterior EliminarNonAlphaCharacters y renombrarla EliminarNonAlphaNumericCharacters

usuario381460
fuente
1

- Primero crea una función

CREATE FUNCTION [dbo].[GetNumericonly]
(@strAlphaNumeric VARCHAR(256))
RETURNS VARCHAR(256)
AS
BEGIN
     DECLARE @intAlpha INT
     SET @intAlpha = PATINDEX('%[^0-9]%', @strAlphaNumeric)
BEGIN
     WHILE @intAlpha > 0
   BEGIN
          SET @strAlphaNumeric = STUFF(@strAlphaNumeric, @intAlpha, 1, '' )
          SET @intAlpha = PATINDEX('%[^0-9]%', @strAlphaNumeric )
   END
END
RETURN ISNULL(@strAlphaNumeric,0)
END

Ahora llame a esta función como

select [dbo].[GetNumericonly]('Abhi12shek23jaiswal')

Su resultado como

1223
Abhishek Jaiswal
fuente
1

Desde la perspectiva del rendimiento, usaría la función en línea:

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION [dbo].[udf_RemoveNumericCharsFromString]
(
@List NVARCHAR(4000)
)
RETURNS TABLE 
AS RETURN

    WITH GetNums AS (
       SELECT TOP(ISNULL(DATALENGTH(@List), 0))
        n = ROW_NUMBER() OVER(ORDER BY (SELECT NULL))
        FROM
          (VALUES (0),(0),(0),(0)) d (n),
          (VALUES (0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) e (n),
          (VALUES (0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) f (n),
          (VALUES (0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) g (n)
            )

    SELECT StrOut = ''+
        (SELECT Chr
         FROM GetNums
            CROSS APPLY (SELECT SUBSTRING(@List , n,1)) X(Chr)
         WHERE Chr LIKE '%[^0-9]%' 
         ORDER BY N
         FOR XML PATH (''),TYPE).value('.','NVARCHAR(MAX)')


   /*How to Use
   SELECT StrOut FROM dbo.udf_RemoveNumericCharsFromString ('vv45--9gut')
   Result: vv--gut
   */
hkravitz
fuente
Sé que este hilo es antiguo, pero una función con valores de tabla en línea es el camino a seguir. El problema con su solución es, porque solo está devolviendo números, este código:), TYPE) .value ('.', 'NVARCHAR (MAX)') no es necesario y ralentizará la función en ~ 50%
Alan Burstein
1

Aquí hay otra solución recursiva de CTE, basada en la respuesta de @Gerhard Weiss aquí . Debería poder copiar y pegar todo el bloque de código en SSMS y jugar con él allí. Los resultados incluyen algunas columnas adicionales para ayudarnos a comprender lo que está sucediendo. Me tomó un tiempo hasta que entendí todo lo que estaba sucediendo con PATINDEX (RegEx) y el CTE recursivo.

DECLARE @DefineBadCharPattern varchar(30)
SET @DefineBadCharPattern = '%[^A-z]%'  --Means anything NOT between A and z characters (according to ascii char value) is "bad"
SET @DefineBadCharPattern = '%[^a-z0-9]%'  --Means anything NOT between a and z characters or numbers 0 through 9 (according to ascii char value) are "bad"
SET @DefineBadCharPattern = '%[^ -~]%'  --Means anything NOT between space and ~ characters (all non-printable characters) is "bad"
--Change @ReplaceBadCharWith to '' to strip "bad" characters from string
--Change to some character if you want to 'see' what's being replaced. NOTE: It must be allowed accoring to @DefineBadCharPattern above
DECLARE @ReplaceBadCharWith varchar(1) = '#'  --Change this to whatever you want to replace non-printable chars with 
IF patindex(@DefineBadCharPattern COLLATE Latin1_General_BIN, @ReplaceBadCharWith) > 0
    BEGIN
        RAISERROR('@ReplaceBadCharWith value (%s) must be a character allowed by PATINDEX pattern of %s',16,1,@ReplaceBadCharWith, @DefineBadCharPattern)
        RETURN
    END
--A table of values to play with:
DECLARE @temp TABLE (OriginalString varchar(100))
INSERT @temp SELECT ' 1hello' + char(13) + char(10) + 'there' + char(30) + char(9) + char(13) + char(10)
INSERT @temp SELECT '2hello' + char(30) + 'there' + char(30)
INSERT @temp SELECT ' 3hello there'
INSERT @temp SELECT ' tab' + char(9) + ' character'
INSERT @temp SELECT 'good bye'

--Let the magic begin:
;WITH recurse AS (
    select
    OriginalString,
    OriginalString as CleanString,
    patindex(@DefineBadCharPattern COLLATE Latin1_General_BIN, OriginalString) as [Position],
    substring(OriginalString,patindex(@DefineBadCharPattern COLLATE Latin1_General_BIN, OriginalString),1) as [InvalidCharacter],
    ascii(substring(OriginalString,patindex(@DefineBadCharPattern COLLATE Latin1_General_BIN, OriginalString),1)) as [ASCIICode]
    from @temp
   UNION ALL
    select
    OriginalString,
    CONVERT(varchar(100),REPLACE(CleanString,InvalidCharacter,@ReplaceBadCharWith)),
    patindex(@DefineBadCharPattern COLLATE Latin1_General_BIN,CleanString) as [Position],
    substring(CleanString,patindex(@DefineBadCharPattern COLLATE Latin1_General_BIN,CleanString),1),
    ascii(substring(CleanString,patindex(@DefineBadCharPattern COLLATE Latin1_General_BIN,CleanString),1))
    from recurse
    where patindex(@DefineBadCharPattern COLLATE Latin1_General_BIN,CleanString) > 0
)
SELECT * FROM recurse
--optionally comment out this last WHERE clause to see more of what the recursion is doing:
WHERE patindex(@DefineBadCharPattern COLLATE Latin1_General_BIN,CleanString) = 0
Baodad
fuente
0

Usando una tabla de números generados por CTE para examinar cada carácter, luego FOR XML para concatenar a una cadena de valores guardados puede ...

CREATE FUNCTION [dbo].[PatRemove](
    @pattern varchar(50),
    @expression varchar(8000) 
    )
RETURNS varchar(8000)
AS
BEGIN
    WITH 
        d(d) AS (SELECT d FROM (VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) digits(d)),
        nums(n) AS (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM d d1, d d2, d d3, d d4),
        chars(c) AS (SELECT SUBSTRING(@expression, n, 1) FROM nums WHERE n <= LEN(@expression))
    SELECT 
        @expression = (SELECT c AS [text()] FROM chars WHERE c NOT LIKE @pattern FOR XML PATH(''));

    RETURN @expression;
END
Dennis Allen
fuente
0
DECLARE @vchVAlue NVARCHAR(255) = 'SWP, Lettering Position 1: 4 Ω, 2: 8 Ω, 3: 16 Ω, 4:  , 5:  , 6:  , Voltage Selector, Solder, 6, Step switch, : w/o fuseholder '


WHILE PATINDEX('%?%' , CAST(@vchVAlue AS VARCHAR(255))) > 0
  BEGIN
    SELECT @vchVAlue = STUFF(@vchVAlue,PATINDEX('%?%' , CAST(@vchVAlue AS VARCHAR(255))),1,' ')
  END 

SELECT @vchVAlue
Mohannad Qattash
fuente
0

de esta manera no funcionó para mí, ya que estaba tratando de mantener las letras árabes, intenté reemplazar la expresión regular pero tampoco funcionó. Escribí otro método para trabajar en el nivel ASCII, ya que era mi única opción y funcionó.

 Create function [dbo].[RemoveNonAlphaCharacters] (@s varchar(4000)) returns varchar(4000)
   with schemabinding
begin
   if @s is null
      return null
   declare @s2 varchar(4000)
   set @s2 = ''
   declare @l int
   set @l = len(@s)
   declare @p int
   set @p = 1
   while @p <= @l begin
      declare @c int
      set @c = ascii(substring(@s, @p, 1))
      if @c between 48 and 57 or @c between 65 and 90 or @c between 97 and 122 or @c between 165 and 253 or @c between 32 and 33
         set @s2 = @s2 + char(@c)
      set @p = @p + 1
      end
   if len(@s2) = 0
      return null
   return @s2
   end

VAMOS

AGOMAA
fuente
-1

Aunque la publicación es un poco antigua, me gustaría decir lo siguiente. El problema que tuve con la solución anterior es que no filtra caracteres como ç, ë, ï, etc. Adapté una función de la siguiente manera (solo usé una cadena de 80 varchar para guardar memoria):

create FUNCTION dbo.udf_Cleanchars (@InputString varchar(80)) 
RETURNS varchar(80) 
AS 

BEGIN 
declare @return varchar(80) , @length int , @counter int , @cur_char char(1) 
SET @return = '' 
SET @length = 0 
SET @counter = 1 
SET @length = LEN(@InputString) 
IF @length > 0 
BEGIN WHILE @counter <= @length 

BEGIN SET @cur_char = SUBSTRING(@InputString, @counter, 1) IF ((ascii(@cur_char) in (32,44,46)) or (ascii(@cur_char) between 48 and 57) or (ascii(@cur_char) between 65 and 90) or (ascii(@cur_char) between 97 and 122))
BEGIN SET @return = @return + @cur_char END 
SET @counter = @counter + 1 
END END 

RETURN @return END
Eric
fuente
Gracias por esto, Eric. Como usted dice, la respuesta marcada en la publicación es muy buena, pero no elimina los caracteres "numéricos" tontos como ½.
Troy
-3

Acabo de encontrar esto integrado en Oracle 10g si eso es lo que estás usando. Tuve que quitar todos los caracteres especiales para comparar un número de teléfono.

regexp_replace(c.phone, '[^0-9]', '')
Lu_Bu
fuente
55
"SQL Server" se refiere específicamente al producto de Microsoft.
nadie