Bagaimana menghapus semua karakter non-alfabet dari string di SQL Server?

Jawaban:

362

Coba fungsi ini:

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

Sebut saja seperti ini:

Select dbo.RemoveNonAlphaCharacters('abc1234def5678ghi90jkl')

Setelah Anda memahami kode, Anda akan melihat bahwa relatif mudah untuk mengubahnya untuk menghapus karakter lain juga. Anda bahkan dapat membuat ini cukup dinamis untuk lulus dalam pola pencarian Anda.

Semoga ini bisa membantu.

George Mastros
sumber
9
Kode ini menghilangkan karakter non-alfa (sehingga angka juga dihapus). Jika Anda ingin meninggalkan angka (hapus karakter non-alfa numerik), maka ... ganti ^ az dengan ^ az ^ 0-9 String pencarian itu muncul dalam kode di dua tempat berbeda. Pastikan untuk mengganti keduanya.
George Mastros
26
Dari komentar Jeff: Saya pikir jika ingin menghapus semua non-huruf dan non-angka, Anda ingin '^ a-z0-9' (versus '^ az ^ 0-9', yang akan meninggalkan ^ dalam string) .
Bahkan Mien
1
+1 George. Ini adalah salah satu tempat di mana kode "Set-Based" dan penggunaan Inline Scalar Functions memiliki kesulitan besar dalam mengalahkan Row-By-Row. Bagus sekali. Saya juga telah menggunakan fungsi "Caps Awal" Anda, yang memiliki bentuk dasar yang sama, selama beberapa tahun, sekarang.
Jeff Moden
6
@Lynchie Ubah '% [^ az]%' Ke '% [^ az]%' Pada dasarnya, cukup tempatkan karakter spasi setelah z.
George Mastros
8
Nama variabel KeepValues ​​sebenarnya berlawanan dengan apa yang seharusnya dilakukan. KeepValues ​​mencantumkan karakter yang perlu dikecualikan ..
nee21
167

Versi parameter dari G Mastros ' jawaban mengagumkan :

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

Hanya alfabet:

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

Hanya numerik:

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

Hanya alfanumerik:

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

Non-alfanumerik:

SELECT dbo.fn_StripCharacters('a1!s2@d3#f4$', 'a-z0-9')
Bahkan Mien
sumber
3
Saya lebih suka versi ini dan membuat adaptasi jawaban G Mastros saya sebelum menggulir ke bawah untuk memilihnya!
Earnshavian
Pola regex tampaknya tidak berfungsi dengan semua spasi putih. Jika saya ingin menghapus semua karakter khusus kecuali karakter alfanumerik dan spasi putih, saya berharap untuk menggunakan SELECT dbo.fn_StripCharacters('a1!s2 spaces @d3# f4$', '^a-z0-9\s')yang masih strip spasi. Saya juga mencoba menggunakan [[:blank:]]tetapi itu merusak fungsi dan tidak ada yang dihapus dari string. Ive terdekat yang saya dapatkan adalah dengan menggunakan: SELECT dbo.fn_StripCharacters('a1!s2 spaces @d3# f4$', '^a-z0-9 ')(hard-coding ruang dalam pola regex). Namun itu tidak menghapus jeda baris.
Billy McKee
2
@BillyMcKee Tambahkan spasi di awal alih-alih menambahkannya di akhir ekspresi reguler. SELECT dbo.fn_StripCharacters('a1!s2 spaces @d3# f4$', '^ a-z0-9')
Mike
8

Percaya atau tidak, dalam sistem saya, fungsi jelek ini berkinerja lebih baik daripada G Mastros yang elegan.

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
sumber
bagaimana dengan koma, titik, ruang, dll?
sojim
seberapa jauh berbeda jika Anda tidak menggunakan ASCIIinteger di sini dan membandingkan langsung output SUBSTRINGdengan beberapa karakter, misalnya: SET @ch=SUBSTRING(@s, @p, 1)danIF @ch BETWEEN '0' AND '9' OR @ch BETWEEN 'a' AND 'z' OR @ch BETWEEN 'A' AND 'Z' ...
S.Serpooshan
Tambahkan DENGAN PEMASANGAN DENGAN fungsi seperti fungsi Anda. Anda menggunakan VARCHAR, fungsinya menggunakan NVARCHAR. Jika parameter yang Anda operasikan ke dalam fungsinya adalah VARCHAR, Anda harus menggunakan VARCHAR alih-alih NVARCHAR di dalam fungsinya, jika tidak, sistem Anda harus memberikan nilai string dari VARCHAR ke NVARCHAR sebelum dapat menjalankan fungsi yang lebih mahal. Bahkan dengan perubahan-perubahan itu, fungsi Anda mungkin masih lebih cepat, tetapi itu adalah beberapa contoh yang dapat saya lihat di mana fungsinya bekerja lebih lambat untuk Anda dalam situasi Anda.
EricI
1
Fungsinya juga menggunakan NVARCHAR (MAX) dan fungsi Anda menggunakan VARCHAR (256). Jika 256 yang Anda butuhkan, ubah fungsinya untuk menggunakan VARCHAR (256) juga dan fungsinya akan bekerja lebih cepat untuk Anda.
EricI
5

Saya tahu bahwa SQL buruk dalam manipulasi string, tetapi saya tidak berpikir akan sesulit ini. Berikut adalah fungsi sederhana untuk menghapus semua angka dari string. Akan ada cara yang lebih baik untuk melakukan ini, tetapi ini adalah awal.

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

Keluaran

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

Babak 2 - Daftar Hitam Berbasis Data

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

Keluaran

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

Tantangan saya kepada pembaca: Dapatkah Anda menjadikan ini lebih efisien? Bagaimana dengan menggunakan rekursi?

Rob Garrison
sumber
Anda mungkin bisa menulis dbo.StripBlacklistCharacters () yang lebih baik tanpa loop menggunakan sommarskog.se/arrays-in-sql-2005.html#tblnum tabel angka yang bergabung ke dalam tabel daftar hitam Anda, tetapi saya terlalu malas hari ini untuk mencobanya sendiri ....
KM.
4

Jika Anda seperti saya dan tidak memiliki akses untuk hanya menambahkan fungsi ke data produksi Anda tetapi masih ingin melakukan pemfilteran seperti ini, inilah solusi SQL murni menggunakan tabel PIVOT untuk menyatukan kembali potongan yang difilter.

NB Saya hardcoded tabel hingga 40 karakter, Anda harus menambahkan lebih banyak jika Anda memiliki string lebih lama untuk difilter.

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
sumber
Solusi ini 2,3x lebih cepat bagi saya daripada menggunakan fungsi pada set 235K baris. Saya juga harus melakukan penggantian 2x, dan menggunakan total empat CTE. Bekerja seperti jagoan.
JJS
4

Setelah melihat semua solusi yang diberikan, saya pikir harus ada metode SQL murni yang tidak memerlukan fungsi atau permintaan CTE / XML, dan tidak melibatkan sulit untuk mempertahankan pernyataan REPLACE bersarang. Ini solusinya:

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

Keuntungan melakukannya dengan cara ini adalah bahwa karakter yang valid terkandung dalam satu string dalam sub kueri sehingga mudah untuk mengkonfigurasi ulang untuk serangkaian karakter yang berbeda.

Kelemahannya adalah Anda harus menambahkan sederetan SQL untuk setiap karakter hingga ukuran kolom Anda. Untuk mempermudah tugas itu, saya hanya menggunakan skrip Powershell di bawah ini, contoh ini untuk 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
sumber
3
Canggung dalam kasus umum, tetapi mudah dan berguna untuk permintaan sekali-pakai dengan kolom sempit.
Eric J.
3

Berikut ini cara lain untuk menghapus karakter non-alfabet menggunakan a iTVF. Pertama, Anda memerlukan pemisah tali berbasis pola. Ini salah satu artikel 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

Sekarang Anda memiliki splitter berbasis pola, Anda perlu membagi string yang cocok dengan pola:

[a-z]

dan kemudian menyatukannya kembali untuk mendapatkan hasil yang diinginkan:

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)

SAMPEL

Hasil:

| 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
sumber
apakah ada manfaat untuk menggunakan ini daripada jawaban lain?
S.Serpooshan
2

Solusi ini, terinspirasi oleh solusi Pak Allen, membutuhkan Numberstabel bilangan bulat (yang harus Anda miliki jika Anda ingin melakukan operasi permintaan yang serius dengan kinerja yang baik). Itu tidak memerlukan CTE. Anda dapat mengubah NOT IN (...)ekspresi untuk mengecualikan karakter tertentu, atau mengubahnya menjadi ekspresi IN (...)ATAU LIKEuntuk mempertahankan hanya karakter tertentu.

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
sumber
Solusi menarik untuk masalah yang tidak terkait.
TaterJuice
2

Inilah solusi yang tidak perlu membuat fungsi atau mendaftar semua instance karakter untuk diganti. Ini menggunakan pernyataan DENGAN rekursif dalam kombinasi dengan PATINDEX untuk menemukan karakter yang tidak diinginkan. Ini akan mengganti semua karakter yang tidak diinginkan dalam kolom - hingga 100 karakter buruk unik yang terkandung dalam string apa pun. (EG "ABC123DEF234" akan berisi 4 karakter buruk 1, 2, 3 dan 4) Batas 100 adalah jumlah maksimum rekursi yang diperbolehkan dalam pernyataan WITH, tetapi ini tidak menentukan batas jumlah baris yang diproses, yang hanya dibatasi oleh memori yang tersedia.
Jika Anda tidak ingin hasil yang berbeda, Anda dapat menghapus dua opsi dari kode.

-- 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;
Pekerjaan Graeme
sumber
1

Saya menempatkan ini di kedua tempat di mana PatIndex disebut.

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

untuk fungsi kustom di atas RemoveNonAlphaCharacters dan menamainya RemoveNonAlphaNumericCharacters

pengguna381460
sumber
1

--Pertama membuat satu fungsi

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

Sekarang panggil fungsi ini seperti

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

Hasilnya seperti

1223
Abhishek Jaiswal
sumber
1

Dari perspektif kinerja, saya akan menggunakan Fungsi Inline:

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
sumber
Saya tahu utas ini sudah tua tetapi, fungsi tabel inline yang dihargai adalah cara yang harus dilakukan. Masalah dengan solusi Anda adalah, karena Anda hanya mengembalikan angka, kode ini:), TYPE) .value ('.', 'NVARCHAR (MAX)') tidak diperlukan dan akan memperlambat fungsinya hingga ~ 50%
Alan Burstein
1

Berikut ini adalah solusi CTE rekursif lain, berdasarkan jawaban @ Grehard Weiss di sini . Anda harus dapat menyalin dan menempelkan seluruh blok kode ke SSMS dan bermain dengannya di sana. Hasilnya mencakup beberapa kolom tambahan untuk membantu kami memahami apa yang terjadi. Butuh beberapa saat sampai saya mengerti semua yang terjadi dengan PATINDEX (RegEx) dan CTE rekursif.

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

Menggunakan tabel angka yang dihasilkan CTE untuk memeriksa setiap karakter, lalu UNTUK XML untuk menyatukan ke string nilai yang disimpan ...

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

cara ini tidak bekerja untuk saya karena saya mencoba untuk menjaga huruf Arab saya mencoba mengganti ekspresi reguler tetapi juga tidak berhasil. saya menulis metode lain untuk bekerja pada tingkat ASCII karena itu satu-satunya pilihan saya dan berhasil.

 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

PERGILAH

AGOMAA
sumber
-1

Meskipun posting agak lama, saya ingin mengatakan yang berikut ini. Masalah yang saya miliki dengan solusi di atas adalah tidak menyaring karakter seperti ç, ë, ï, dll. Saya mengadaptasi fungsi sebagai berikut (Saya hanya menggunakan string 80 varchar untuk menghemat memori):

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
sumber
Terima kasih untuk ini, Eric. Seperti yang Anda katakan, jawaban yang ditandai pos sangat bagus, tetapi tidak menghilangkan karakter "numerik" yang konyol seperti ½.
troy
-3

Saya baru saja menemukan ini dibangun ke Oracle 10g jika itu yang Anda gunakan. Saya harus menghapus semua karakter khusus untuk membandingkan nomor telepon.

regexp_replace(c.phone, '[^0-9]', '')
Lu_Bu
sumber
5
"SQL Server" merujuk secara khusus ke produk Microsoft.
tidak ada yang