Как убрать все не алфавитные символы из строки в SQL Server?

172

Как вы можете удалить из строки все символы, которые не являются буквенными?

А как насчет не буквенно-цифровых?

Это должна быть пользовательская функция или есть более обобщенные решения?

Даже Миен
источник

Ответы:

362

Попробуйте эту функцию:

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

Назовите это так:

Select dbo.RemoveNonAlphaCharacters('abc1234def5678ghi90jkl')

Как только вы поймете код, вы увидите, что его относительно просто изменить, чтобы удалить другие символы. Вы даже можете сделать это достаточно динамичным, чтобы передать ваш шаблон поиска.

Надеюсь, поможет.

Джордж Мастрос
источник
9
Этот код удаляет не-буквенные символы (поэтому цифры также удаляются). Если вы хотите оставить цифры (удалить не алфавитно-цифровые символы), то ... замените ^ az на ^ az ^ 0-9. Эта строка поиска появляется в коде в двух разных местах. Обязательно замените их обоих.
Джордж Мастрос
26
Из комментария Джеффа: Я думаю, что если вы хотите удалить все не буквы и не числа, вы бы хотели '^ a-z0-9' (против '^ az ^ 0-9', который оставил бы ^ в строке) ,
Даже Mien
1
+1 Джордж. Это одно из тех мест, где «основанный на множестве» код и использование встроенных скалярных функций испытывают большие трудности при прохождении строки за строкой. Красиво сделано. Я также использую вашу функцию «Начальные буквы», которая имеет такую ​​же базовую форму, уже пару лет.
Джефф Моден
6
@Lynchie Изменить '% [^ az]%' на '% [^ az]%' В основном, просто ставьте пробел после z.
Джордж Мастрос
8
Имя переменной KeepValues ​​фактически противоположно тому, для чего она предназначена. KeepValues ​​перечисляет символы, которые должны быть исключены ..
nee21
167

Параметризованная версия 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

Только в алфавитном порядке:

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

Только числовые:

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

Только буквенно-цифровой:

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

Не буквенно-цифровые:

SELECT dbo.fn_StripCharacters('a1!s2@d3#f4$', 'a-z0-9')
Даже Миен
источник
3
Я предпочитаю эту версию и создал мою адаптацию ответа G Mastros, прежде чем прокрутить вниз, чтобы проголосовать!
Заработок
Шаблон регулярных выражений, похоже, не работает со всеми пробелами. Если я хочу удалить все специальные символы, кроме буквенно-цифровых символов и пробелов, я бы хотел использовать, SELECT dbo.fn_StripCharacters('a1!s2 spaces @d3# f4$', '^a-z0-9\s')которые по-прежнему удаляют пробелы. Я также пытался использовать, [[:blank:]]но это нарушает функцию, и ничего не удаляется из строки. Ближайший Ive получил с помощью: SELECT dbo.fn_StripCharacters('a1!s2 spaces @d3# f4$', '^a-z0-9 ')(жесткое кодирование пробела в шаблоне регулярных выражений). Однако это не удаляет разрывы строк.
Билли Макки
2
@BillyMcKee Добавьте пробел в начале, а не в конце регулярного выражения. SELECT dbo.fn_StripCharacters('a1!s2 spaces @d3# f4$', '^ a-z0-9')
Майк
8

Верьте или нет, в моей системе эта уродливая функция работает лучше, чем элегантная 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
Дж Брюн
источник
как насчет общих запятых, точек, пробелов и т. д.?
Соджим
насколько они отличаются, если вы не используете ASCIIздесь целое число и сравниваете напрямую вывод SUBSTRINGс некоторыми символами, например: SET @ch=SUBSTRING(@s, @p, 1)andIF @ch BETWEEN '0' AND '9' OR @ch BETWEEN 'a' AND 'z' OR @ch BETWEEN 'A' AND 'Z' ...
S.Serpooshan
Добавьте WITH SCHEMABINDING к его функции, как ваша функция. Вы используете VARCHAR, его функция использует NVARCHAR. Если параметры, которые вы передаете в его функцию - это VARCHAR, вы должны использовать VARCHAR вместо NVARCHAR в своей функции, иначе вашей системе потребуется преобразовать строковые значения из VARCHAR в NVARCHAR, прежде чем она сможет выполнять более дорогую функцию. Даже с этими изменениями ваша функция все еще может быть быстрее, но вот несколько примеров, которые я вижу, где его функция может работать медленнее для вас в вашей ситуации.
EricI
1
Его функция также использует NVARCHAR (MAX), а ваша функция использует VARCHAR (256). Если 256 - это все, что вам нужно, измените его функцию на использование VARCHAR (256), и эта функция будет работать для вас быстрее.
EricI
5

Я знал, что SQL плохо работает со строками, но не думал, что это будет так сложно. Вот простая функция, чтобы вырезать все числа из строки. Там были бы лучшие способы сделать это, но это только начало.

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

Вывод

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

Раунд 2 - черный список данных

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

Вывод

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

Мой вызов читателям: Можете ли вы сделать это более эффективным? Как насчет использования рекурсии?

Роб Гаррисон
источник
Вы могли бы, вероятно, написать лучший dbo.StripBlacklistCharacters () без цикла, используя sommarskog.se/arrays-in-sql-2005.html#tblnum таблицу чисел, включенную в таблицу черного списка, но сегодня я слишком ленив, чтобы попробовать это сам ....
км.
4

Если вы похожи на меня и не имеете доступа просто добавлять функции к своим производственным данным, но все же хотите выполнять такую ​​фильтрацию, вот чистое решение SQL, использующее таблицу PIVOT для повторного объединения отфильтрованных частей.

NB Я жестко закодировал таблицу до 40 символов, вам придется добавить больше, если у вас есть более длинные строки для фильтрации.

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
Кайл Хейл
источник
Для меня это решение было в 2,3 раза быстрее, чем использование функции для набора из 235 тыс. Строк. Я также должен был сделать 2 замены, и использовал в общей сложности четыре CTE. Работал как чемпион.
JJS
4

Посмотрев на все приведенные решения, я подумал, что должен существовать метод чистого SQL, который не требует функции или запроса CTE / XML и не требует сложного обслуживания вложенных операторов REPLACE. Вот мое решение:

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

Преимущество такого способа состоит в том, что в подстроке содержатся допустимые символы, что упрощает перенастройку для другого набора символов.

Недостатком является то, что вы должны добавить строку SQL для каждого символа вплоть до размера вашего столбца. Чтобы упростить эту задачу, я просто использовал приведенный ниже скрипт Powershell, например, для VARCHAR (64):

1..64 | % {
  "    + CASE WHEN a NOT LIKE '%' + SUBSTRING(x, {0}, 1) + '%' THEN '' ELSE SUBSTRING(x, {0}, 1) END" -f $_
} | clip.exe
Дейв Секстон
источник
3
Неудобно в общем случае, но легко и полезно для разового запроса с узким столбцом.
Эрик Дж.
3

Вот еще один способ удалить не алфавитные символы, используя iTVF. Во-первых, вам нужен сплиттер на основе шаблона. Вот один взят из Dwain лагеря статьи :

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

Теперь, когда у вас есть сплиттер на основе шаблона, вам нужно разделить строки, соответствующие шаблону:

[a-z]

а затем объединить их обратно, чтобы получить желаемый результат:

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)

ОБРАЗЕЦ

Результат:

| 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 |
Феликс Памиттан
источник
есть ли преимущество, чтобы использовать это перед другими ответами?
С.Серпушан
2

Это решение, основанное на решении г-на Аллена, требует Numbersтаблицы целых чисел (которая должна быть у вас под рукой, если вы хотите выполнять серьезные операции с запросами с хорошей производительностью). Не требует CTE. Вы можете изменить NOT IN (...)выражение, чтобы исключить определенные символы, или изменить его на выражение IN (...)ИЛИ, LIKEчтобы сохранить только определенные символы.

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 ...
Джей Биенвену
источник
Интересное решение не связанной проблемы.
TaterJuice
2

Вот решение, которое не требует создания функции или перечисления всех экземпляров символов для замены. Он использует рекурсивный оператор WITH в сочетании с PATINDEX для поиска нежелательных символов. Он заменит все нежелательные символы в столбце - до 100 уникальных плохих символов, содержащихся в любой заданной строке. (Например, «ABC123DEF234» будет содержать 4 неправильных символа 1, 2, 3 и 4). Ограничение 100 - это максимальное количество рекурсий, допустимое в операторе WITH, но это не накладывает ограничения на число обрабатываемых строк, что ограничено только доступной памятью.
Если вам не нужны результаты DISTINCT, вы можете удалить две опции из кода.

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

Я положил это в обоих местах, где называется PatIndex.

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

для пользовательской функции выше RemoveNonAlphaCharacters и переименовал ее RemoveNonAlphaNumericCharacters

user381460
источник
1

- Сначала создайте одну функцию

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

Теперь назовите эту функцию как

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

Его результат как

1223
Абхишек Джайсвал
источник
1

С точки зрения производительности я бы использовал встроенную функцию:

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
источник
Я знаю, что этот поток старый, но встроенная табличная функция - это путь. Проблема с вашим решением в том, что вы только возвращаете числа, этот код :), TYPE) .value ('.', 'NVARCHAR (MAX)') не нужен и замедлит работу функции на ~ 50%
Алан Бурштейн
1

Вот еще одно рекурсивное решение CTE, основанное на ответе @Gerhard Weiss здесь . Вы должны быть в состоянии скопировать и вставить весь блок кода в SSMS и поиграть с ним там. Результаты включают несколько дополнительных столбцов, чтобы помочь нам понять, что происходит. Мне потребовалось некоторое время, чтобы понять все, что происходит с PATINDEX (RegEx) и рекурсивным CTE.

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
источник
0

Используя таблицу сгенерированных CTE чисел для проверки каждого символа, затем FOR XML для констатации в строку сохраненных значений, которые вы можете ...

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

этот способ не работал для меня, так как я пытался сохранить арабские буквы, которые я пытался заменить регулярным выражением, но также он не работал. я написал другой метод для работы на уровне ASCII, так как это был мой единственный выбор, и он работал.

 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

ИДТИ

AGOMAA
источник
-1

Хотя пост немного устарел, я хотел бы сказать следующее. Проблема, с которой я столкнулся при решении выше, состоит в том, что он не отфильтровывает символы, такие как ç, ë, ï и т. Д. Я адаптировал функцию следующим образом (я использовал только строку из 80 varchar для экономии памяти):

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
Эрик
источник
Спасибо тебе за это, Эрик. Как вы говорите, сообщение с пометкой «ответ» очень хорошо, но оно не снимает глупых «числовых» символов, таких как ½.
Троя
-3

Я только что нашел это встроенным в Oracle 10g, если это то, что вы используете. Мне пришлось убрать все специальные символы для сравнения номера телефона.

regexp_replace(c.phone, '[^0-9]', '')
Lu_Bu
источник
5
«SQL Server» относится конкретно к продукту Microsoft.
никто не