如何替换字符串中的所有特殊字符

时间:2019-04-10 07:50:34

标签: sql sql-server string tsql

我有一个包含以下列的表格:

dbo.SomeInfo
  - Id
  - Name
  - InfoCode

现在我需要将上表的InfoCode更新为

Update  dbo.SomeInfo
Set InfoCode= REPLACE(Replace(RTRIM(LOWER(Name)),' ','-'),':','')

这会用-替换所有空格,并使用小写名称

当我检查信息代码时,我看到有一些带有特殊字符的名称,例如

Cathe Friedrich''s Low Impact
coffeyfit-cardio-box-&-burn
Jillian Michaels: Cardio

然后我以此手动编写更新sql

 Update dbo.SomeInfo
 SET InfoCode= 'cathe-friedrichs-low-impact'
 where Name ='Cathe Friedrich''s Low Impact '

现在,这种解决方案对我来说并不现实。我检查了以下与正则表达式及其周围其他人相关的链接。

但是他们都没有达到要求。

我需要的是是否有其他[a-z0-9]字符替换它-并且在InfoCode中也不应连续字符

以上Update sql已将InfoCode的某些值设置为the-dancer's-workout®----starter-package

某些名称的值为

Sleek Technique™
The Dancer's-workout®

如何编写可以处理所有此类特殊字符的Update sql?

3 个答案:

答案 0 :(得分:1)

这种方法是完全不可行的:

首先,我们需要一个带有一些测试数据的模拟表

DECLARe @SomeInfo TABLE (Id INT IDENTITY, InfoCode VARCHAR(100));
INSERT INTO @SomeInfo (InfoCode) VALUES
 ('Cathe Friedrich''s Low Impact')
,('coffeyfit-cardio-box-&-burn')
,('Jillian Michaels: Cardio')
,('Sleek Technique™')
,('The Dancer''s-workout®');

-这是查询

WITH cte AS
(
    SELECT 1 AS position
          ,si.Id
          ,LOWER(si.InfoCode) AS SourceText
          ,SUBSTRING(LOWER(si.InfoCode),1,1) AS OneChar
    FROM @SomeInfo si

    UNION ALL

    SELECT cte.position +1
          ,cte.Id
          ,cte.SourceText
          ,SUBSTRING(LOWER(cte.SourceText),cte.position+1,1) AS OneChar
    FROM cte
    WHERE position < DATALENGTH(SourceText)
)
,Cleaned AS
(
    SELECT cte.Id
          ,(
            SELECT CASE WHEN ASCII(cte2.OneChar) BETWEEN 65 AND 90 --A-Z
                          OR ASCII(cte2.OneChar) BETWEEN 97 AND 122--a-z
                          OR ASCII(cte2.OneChar) BETWEEN 48 AND 57 --0-9
                          --You can easily add more ranges
                        THEN cte2.OneChar ELSE '-' 
                          --You can easily nest another CASE to deal with special characters like the single quote in your examples... 
                   END 
            FROM cte AS cte2
            WHERE cte2.Id=cte.Id
            ORDER BY cte2.position
            FOR XML PATH('')
           ) AS normalised
    FROM cte
    GROUP BY cte.Id
)
,NoDoubleHyphens AS
(
    SELECT REPLACE(REPLACE(REPLACE(normalised,'-','<>'),'><',''),'<>','-') AS normalised2
    FROM Cleaned
)
SELECT CASE WHEN RIGHT(normalised2,1)='-' THEN SUBSTRING(normalised2,1,LEN(normalised2)-1) ELSE normalised2 END AS FinalResult 
FROM NoDoubleHyphens;

第一个CTE将逐个字符地递归地遍历字符串,并返回一个非常细的集,每个字符一行。

第二个CTE随后将GROUP个ID。这允许使用相关子查询,其中实际检查是使用ASCII范围执行的。 FOR XML PATH('')用于重新连接字符串。对于SQL Server 2017+,我建议改用STRING_AGG()

第三CTE将使用众所周知的技巧来消除角色的多次出现。取两个永远不会出现在您的字符串中的字符,我使用<>。像a--b---c这样的字符串将以a<><>b<><><>c的形式返回。将><替换为空后,我们得到a<>b<>c。好吧,就是这样...

最后的SELECT将删除结尾的连字符。如果需要,您可以添加类似的逻辑以消除前导连字符。在v2017 +中,TRIM('-')可以简化此操作...

结果

cathe-friedrich-s-low-impact
coffeyfit-cardio-box-burn
jillian-michaels-cardio
sleek-technique
the-dancer-s-workout

答案 1 :(得分:0)

使用NGrams8K,您可以将字符串拆分为字符,然后代替替换每个不可接受的字符,只保留某些字符:

SELECT (SELECT '' + CASE WHEN N.token COLLATE Latin1_General_BIN LIKE '[A-z0-9]'THEN token ELSE '-' END
        FROM dbo.NGrams8k(V.S,1) N
        ORDER BY position
        FOR XML PATH(''))
FROM (VALUES('Sleek Technique™'),('The Dancer''s-workout®'))V(S);

我在这里使用COLLATE,因为在我的实例中默认排序规则是'™',因此我使用二进制排序规则。您可能要使用COLLATE将字符串切换回子查询之外的原始排序规则。

答案 2 :(得分:0)

您可以为类似的内容创建用户定义的功能。

然后在更新中使用UDF。

CREATE FUNCTION [dbo].LowerDashString (@str varchar(255))
RETURNS varchar(255)
AS
BEGIN
    DECLARE @result varchar(255);
    DECLARE @chr varchar(1);
    DECLARE @pos int;
    SET @result = '';
    SET @pos = 1;

    -- lowercase the input and remove the single-quotes
    SET @str = REPLACE(LOWER(@str),'''','');

    -- loop through the characters 
    -- while replacing anything that's not a letter to a dash
    WHILE @pos <= LEN(@str)
    BEGIN

      SET @chr = SUBSTRING(@str, @pos, 1)

      IF @chr LIKE '[a-z]' SET @result += @chr;
      ELSE SET @result += '-';

      SET @pos += 1;
    END;

    -- SET @result = TRIM('-' FROM @result); -- SqlServer 2017 and beyond

    -- multiple dashes to one dash
    WHILE @result LIKE '%--%' SET @result = REPLACE(@result,'--','-');

    RETURN @result;
END;
GO

使用以下功能的示例片段:

-- using a table variable for demonstration purposes
declare @SomeInfo table (Id int primary key identity(1,1) not null, InfoCode varchar(100) not null);

-- sample data
insert into @SomeInfo (InfoCode) values
('Cathe Friedrich''s Low Impact'),
('coffeyfit-cardio-box-&-burn'),
('Jillian Michaels: Cardio'),
('Sleek Technique™'),
('The Dancer''s-workout®');

update @SomeInfo
set InfoCode = dbo.LowerDashString(InfoCode)
where (InfoCode LIKE '%[^A-Z-]%' OR InfoCode != LOWER(InfoCode));

select * 
from @SomeInfo;

结果:

Id  InfoCode
--  -----------------------------
1   cathe-friedrichs-low-impact
2   coffeyfit-cardio-box-burn
3   jillian-michaels-cardio
4   sleek-technique-
5   the-dancers-workout-