如何替换字符串中的所有特殊字符
Posted
技术标签:
【中文标题】如何替换字符串中的所有特殊字符【英文标题】:How to replace all special characters in string 【发布时间】:2019-08-31 14:34:42 【问题描述】:我有一个包含以下列的表格:
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 '
现在,这个解决方案对我来说是不现实的。我检查了以下与 Regex 相关的链接及其周围的其他链接。
UPDATE and REPLACE part of a string https://www.codeproject.com/Questions/456246/replace-special-characters-in-sql但没有一个达到要求。
我需要的是如果有任何其他字符 [a-z0-9] 替换它 - & 也不应该是连续的 - 在 InfoCode 中
上面的Update sql已经将InfoCode的一些值设置为the-dancer's-workout®----starter-package
一些名称的价值为
Sleek Technique™
The Dancer's-workout®
如何编写可以处理所有此类特殊字符的更新 sql?
【问题讨论】:
【参考方案1】:使用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】:这种方法是完全可内联的:
首先我们需要一个带有一些测试数据的模型表:
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
Ids。这允许相关子查询,其中使用 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
【讨论】:
【参考方案3】:您可以为类似的东西创建一个用户定义的函数。
然后在更新中使用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
使用函数的示例 sn-p:
-- 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-
【讨论】:
以上是关于如何替换字符串中的所有特殊字符的主要内容,如果未能解决你的问题,请参考以下文章