Замініть спеціальні символи в стовпці пробілом


10

Я намагаюся написати запит, який замінює спеціальні символи пробілом. Нижче код допомагає визначити рядки. (дійсні буквено-цифрові символи, кома та пробіл):

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

Як я можу інтегрувати функцію заміни у оператор select, щоб усі символи, крім буквено-цифрових, комах та пробілів у наборі результатів, були замінені на '' (пробіл). Цей не працює:

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

Відповіді:


11

Якщо ви гарантовано будете використовувати лише 26 літер англійського алфавіту США (як великі, так і малі версії), то впевнені, що ви можете піти з використанням LIKEта / або PATINDEXз простою позначенням діапазону [a-z](ви б не стали потрібно використовувати верхній регістр "Z" при використанні нечутливого до регістру Collation).

Але, якщо ви можете отримати символи , які не знайшли в ан-США алфавіт ще доступні в різних кодових сторінок / Collations для VARCHARданих (наприклад , Þ= Latin капітал «Торн» = SELECT CHAR(0xDE)), то вам , можливо , буде потрібно включити тих , хто в класі символів: [a-z0-9, Þ]. Звичайно, що це зайві символи - це на основі кодової сторінки.

Також майте на увазі, що і тип Collation (SQL Server проти Windows), і налаштування чутливості (випадок, акцент тощо, чутливий та нечутливий) впливатимуть на те, які символи будуть включені до певного діапазону. Наприклад, зібрання SQL Server сортують великі і малі літери у зворотному порядку, як і Windows Collations. Тобто, якщо припустити, що залежно від регістру зіставлення для обох типів збірок, один зробить, AaBb...а інший зробить aAbB.... Ефект буде таким, що aбуде в межах A-Zодного з них, а не для іншого. І діапазон a-Zне відповідає жодним символам у двійковому зіставленні (який закінчується на _BINабо _BIN2, але не використовується _BIN), враховуючи, що значення Aстановить 65 іaце 97, отже, це недійсний діапазон від 97 до 65 ;-). Тут є занадто багато варіантів, щоб навести приклади, тому я спробую опублікувати детальне пояснення у своєму блозі якось скоро (а потім оновлю це за посиланням на нього). Однак, якщо ви будете суворо ставитися до прийняття лише американських англійських символів (навіть якщо ви можете отримати дійсні листи з інших мов), тоді, найкращим варіантом, можливо, буде використання наступного шаблону та зіставлення:

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

Тепер, якщо ви підтримуєте NVARCHARдані і можете отримати символи "word" з різних мов, T-SQL не буде корисною, оскільки не має реального способу розмежувати ці речі. У цьому випадку слід використовувати регулярне вираження (RegEx) - конкретно Replaceметод / функцію - і вони доступні лише через SQLCLR. Далі наведено приклад заміни декількох "спеціальних" символів, однак залишивши всі дійсні букви принаймні однією мовою:

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

Повернення:

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

Вираз RegEx означає:

  • \W= «втеча» RegEx, що означає «будь- який символ, який не є словом»
  • \p{Pc}= "Unicode" категорія "пунктуації, з'єднувач" (це потрібно для відповідності лише тому, що ця "категорія" спеціально виключається під час \Wвтечі)
  • -[,]= віднімання класу (це потрібно для виключення коми з відповідності як "спеціальних", оскільки вони включені у \Wвихідний)

Можна оновити таблицю, просто видавши:

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

Зверніть увагу, що для цих прикладів я використав дві функції, доступні у бібліотеці SQL # для безкоштовної версії функцій SQLCLR, які я створив (але знову ж таки, це безкоштовно). Також зауважте, що я використовував "4k" версії, які швидше завдяки використанню NVARCHAR(4000)замість NVARCHAR(MAX)типів параметрів. Якщо ваші дані використовуються NVARCHAR(MAX), то просто видаліть "4k" з назв функцій.

Також дивіться:


5

У мене тут посада, яка робить щось подібне .

В основному я використовую рекурсивний CTE для перегляду циклу знову і знову, замінюючи одночасно один "поганий" символ. Я використовую STUFF для зняття символу 1 (хоча ви можете використовувати його для заміни пробілом) та PATINDEX, щоб знайти місце символу, який я хочу видалити. Ви можете трохи змінити його, щоб робити те, що шукаєте. Однак він створює "хороший" список, він фактично не оновлює існуючий список.

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

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

Ви повинні мати можливість змінити нижню частину, щоб зробити оновлення, а не просто запит, але я насправді цього не намагався. Я впевнений, що це виглядатиме приблизно так:

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

Що стосується масштабованості, я повернув ~ 170 тис. Очищених рядків за 30 секунд. Знову не впевнений, що робити оновлення, але це було на моєму ноутбуці, який досить повільний, лише 6 ГБ оперативної пам’яті.


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

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

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

END
Select @NewString
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.