Come rimuovere tutti i caratteri non alfabetici dalla stringa in SQL Server?


Risposte:


362

Prova questa funzione:

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

Chiamalo così:

Select dbo.RemoveNonAlphaCharacters('abc1234def5678ghi90jkl')

Una volta compreso il codice, dovresti vedere che è relativamente semplice modificarlo per rimuovere anche altri caratteri. Potresti persino rendere questa dinamica abbastanza per passare nel tuo modello di ricerca.

Spero che sia d'aiuto.


9
Questo codice rimuove i caratteri non alfabetici (quindi vengono rimossi anche i numeri). Se si desidera lasciare i numeri (rimuovere i caratteri numerici non alfa), quindi ... sostituire ^ az con ^ az ^ 0-9 Quella stringa di ricerca appare nel codice in due punti diversi. Assicurati di sostituirli entrambi.
George Mastros,

26
Dal commento di Jeff: Penso che se volessi rimuovere tutte le non lettere e non numeri, vorrai '^ a-z0-9' (contro '^ az ^ 0-9', che lascerebbe ^ nella stringa) .
Anche Mien,

1
+1 Giorgio. Questo è uno di quei posti in cui il codice "Set-Based" e l'uso delle funzioni scalari incorporate hanno grandi difficoltà a battere riga per riga. Ben fatto. Ho anche usato la tua funzione "Initial Caps", che ha la stessa forma di base, da un paio d'anni, ormai.
Jeff Moden,

6
@Lynchie Modifica '% [^ az]%' In '% [^ az]%' In pratica, inserisci uno spazio dopo la z.
George Mastros,

8
Il nome della variabile KeepValues ​​è in realtà l'opposto di ciò che deve fare. KeepValues ​​elenca i personaggi che devono essere esclusi ..
nee21

167

Versione con parametri di G Mastros ' risposta impressionante :

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 alfabetico:

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

Solo numerico:

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

Solo alfanumerico:

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

Non alfanumerico:

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

3
Preferisco questa versione e ho creato il mio adattamento della risposta di G Mastros prima di scorrere verso il basso per votarla!
guadshavian,

Il modello regex non sembra funzionare con tutti gli spazi bianchi. Se desidero eliminare tutti i caratteri speciali tranne i caratteri alfanumerici e gli spazi bianchi, mi aspetterei di utilizzare quelli SELECT dbo.fn_StripCharacters('a1!s2 spaces @d3# f4$', '^a-z0-9\s')che rimuovono gli spazi bianchi. Ho anche provato a usare [[:blank:]]ma questo interrompe la funzione e nulla viene rimosso dalla stringa. Il più vicino che ho ottenuto è usando: SELECT dbo.fn_StripCharacters('a1!s2 spaces @d3# f4$', '^a-z0-9 ')(hardcoding di uno spazio nel modello regex). Tuttavia, ciò non rimuove le interruzioni di riga.
Billy McKee,

2
@BillyMcKee Aggiungi lo spazio all'inizio invece di aggiungerlo alla fine dell'espressione regolare. SELECT dbo.fn_StripCharacters('a1!s2 spaces @d3# f4$', '^ a-z0-9')
Mike,

8

Che ci crediate o no, nel mio sistema questa brutta funzione svolge meglio di G Mastros elegante.

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

che dire di virgole, punti, spazi comuni, ecc.?
sojim,

quanto si differenzia se non si utilizza ASCIIqui un numero intero e si confronta direttamente l'output di SUBSTRINGcon alcuni caratteri, ad esempio: SET @ch=SUBSTRING(@s, @p, 1)eIF @ch BETWEEN '0' AND '9' OR @ch BETWEEN 'a' AND 'z' OR @ch BETWEEN 'A' AND 'Z' ...
S.Serpooshan

Aggiungi WITH SCHEMABINDING alla sua funzione come ha fatto la tua funzione. Stai usando VARCHAR, la sua funzione sta usando NVARCHAR. Se i parametri che stai passando nella sua funzione sono VARCHAR, dovresti usare VARCHAR invece di NVARCHAR all'interno della sua funzione, altrimenti il ​​tuo sistema dovrà trasmettere i valori di stringa da VARCHAR a NVARCHAR prima di poter eseguire la funzione che è più costosa. Anche con quei cambiamenti la tua funzione potrebbe essere ancora più veloce, ma questi sono alcuni esempi che posso vedere dove la sua funzione potrebbe funzionare più lentamente per te nella tua situazione.
Eric

1
La sua funzione utilizza anche NVARCHAR (MAX) e la tua funzione utilizza VARCHAR (256). Se 256 è tutto ciò di cui hai bisogno, cambia la sua funzione per usare anche VARCHAR (256) e la sua funzione funzionerà più velocemente per te.
Eric

5

Sapevo che SQL non era in grado di manipolare le stringhe, ma non pensavo che sarebbe stato così difficile. Ecco una semplice funzione per eliminare tutti i numeri da una stringa. Ci sarebbero modi migliori per farlo, ma questo è un inizio.

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

Produzione

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

Round 2 - Blacklist basata sui dati

-- ============================================
-- 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

Produzione

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

La mia sfida per i lettori: puoi renderlo più efficiente? Che dire dell'utilizzo della ricorsione?


probabilmente potresti scrivere un dbo.StripBlacklistCharacters () migliore senza un ciclo usando sommarskog.se/arrays-in-sql-2005.html#tblnum tabella dei numeri unita alla tua tabella della black list, ma oggi sono troppo pigro per provarlo me stesso ....
KM.

4

Se sei come me e non hai accesso solo ad aggiungere funzioni ai tuoi dati di produzione ma vuoi comunque eseguire questo tipo di filtro, ecco una soluzione SQL pura che utilizza una tabella PIVOT per rimettere insieme i pezzi filtrati.

NB Ho codificato la tabella fino a 40 caratteri, dovrai aggiungere altro se hai stringhe più lunghe da filtrare.

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

Questa soluzione è stata 2,3 volte più veloce per me rispetto all'utilizzo di una funzione su un set di 235 KB di righe. Ho anche dovuto fare 2x sostituzioni e ho usato un totale di quattro CTE. Ha funzionato come un campione.
JJS,

4

Dopo aver esaminato tutte le soluzioni fornite, ho pensato che ci dovesse essere un metodo SQL puro che non richiede una funzione o una query CTE / XML e che non comporta difficoltà nel mantenere le istruzioni nidificate REPLACE. Ecco la mia soluzione:

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

Il vantaggio di farlo in questo modo è che i caratteri validi sono contenuti in una stringa nella query secondaria, facilitando la riconfigurazione per un diverso set di caratteri.

Il rovescio della medaglia è che devi aggiungere una riga di SQL per ogni carattere fino alla dimensione della colonna. Per semplificare questo compito ho appena usato lo script Powershell di seguito, questo esempio se per un VARCHAR (64):

1..64 | % {
  "    + CASE WHEN a NOT LIKE '%' + SUBSTRING(x, {0}, 1) + '%' THEN '' ELSE SUBSTRING(x, {0}, 1) END" -f $_
} | clip.exe

3
Imbarazzante nel caso generale, ma facile e utile per una query una tantum con una colonna stretta.
Eric J.

3

Ecco un altro modo per rimuovere caratteri non alfabetici usando un iTVF. Innanzitutto, è necessario uno splitter di stringhe basato su pattern. Ecco uno preso da Dwain di Campo articolo :

-- 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

Ora che hai uno splitter basato su pattern, devi dividere le stringhe che corrispondono al pattern:

[a-z]

e poi concatenarli nuovamente per ottenere il risultato desiderato:

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)

CAMPIONE

Risultato:

| 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 |

c'è qualche vantaggio nell'usarlo su altre risposte?
S. Serpooshan,

2

Questa soluzione, ispirata alla soluzione di Mr. Allen, richiede una Numberstabella di numeri interi (che dovresti avere a portata di mano se vuoi fare operazioni di query serie con buone prestazioni). Non richiede un CTE. È possibile modificare l' NOT IN (...)espressione per escludere caratteri specifici o modificarla in un'espressione IN (...)OR LIKEper conservare solo determinati caratteri.

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 ...

Soluzione interessante a un problema non correlato.
TaterJuice

2

Ecco una soluzione che non richiede la creazione di una funzione o l'elenco di tutte le istanze di caratteri da sostituire. Utilizza un'istruzione WITH ricorsiva in combinazione con un PATINDEX per trovare caratteri indesiderati. Sostituirà tutti i caratteri indesiderati in una colonna - fino a 100 caratteri univoci non validi contenuti in una determinata stringa. (Ad esempio "ABC123DEF234" conterrebbe 4 caratteri non validi 1, 2, 3 e 4) Il limite 100 è il numero massimo di ricorsioni consentite in un'istruzione WITH, ma ciò non impone un limite al numero di righe da elaborare, che è limitato solo dalla memoria disponibile.
Se non si desidera risultati DISTINCT, è possibile rimuovere le due opzioni dal codice.

-- 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;

1

L'ho messo in entrambi i posti in cui si chiama PatIndex.

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

per la funzione personalizzata sopra RemoveNonAlphaCharacters e rinominata RemoveNonAlphaNumericCharacters


1

- Prima crea una funzione

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

Ora chiama questa funzione come

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

Il suo risultato è simile

1223

1

Dal punto di vista delle prestazioni userei la funzione in linea:

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
   */

So che questo thread è vecchio ma, una funzione in linea con valori di tabella è la strada da percorrere. Il problema con la tua soluzione è che, poiché stai restituendo solo numeri, questo codice:), TYPE) .value ('.', 'NVARCHAR (MAX)') non è necessario e rallenterà la funzione di ~ 50%
Alan Burstein il

1

Ecco un'altra soluzione CTE ricorsiva, basata sulla risposta di @Gerhard Weiss qui . Dovresti essere in grado di copiare e incollare l'intero blocco di codice in SSMS e giocare con esso lì. I risultati includono alcune colonne extra per aiutarci a capire cosa sta succedendo. Mi ci è voluto un po 'di tempo prima di aver capito tutto quello che stava succedendo sia con PATINDEX (RegEx) che con il CTE ricorsivo.

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

0

Utilizzando una tabella di numeri generati CTE per esaminare ogni carattere, quindi FOR XML per concatenare una stringa di valori mantenuti è possibile ...

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

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

0

in questo modo non ha funzionato per me mentre cercavo di mantenere le lettere arabe che ho provato a sostituire l'espressione regolare ma anche non ha funzionato. ho scritto un altro metodo per lavorare a livello ASCII in quanto era la mia unica scelta e ha funzionato.

 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

PARTIRE


-1

Sebbene la posta sia un po 'vecchia, vorrei dire quanto segue. Il problema che ho avuto con la soluzione sopra è che non filtra i caratteri come ç, ë, ï, ecc. Ho adattato una funzione come segue (ho usato solo una stringa varchar 80 per risparmiare 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

Grazie per questo, Eric. Come dici tu, la risposta contrassegnata dal post è molto buona, ma non toglie caratteri "numerici" come ½.
troy,

-3

Ho appena trovato questo integrato in Oracle 10g se è quello che stai usando. Ho dovuto eliminare tutti i caratteri speciali per confrontare un numero di telefono.

regexp_replace(c.phone, '[^0-9]', '')

5
"SQL Server" si riferisce specificamente al prodotto Microsoft.
nessuno
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.