PATINDEX 模式替换*不是*第一个字符的字符
PATINDEX pattern to replace character that is *not* first character
我正在尝试部分 'leet-ify' 一个词,方法是从一组预定义的可替换字符中取出一个字符,并将其替换为类似于字母的 number/special 字符更换。不过我不想替换第一个字符。
早些时候我得到一个词,我确保在可替换字母集中的第一个字母之后至少有一个字母,并将其放入 @Word
变量中。然后我使用以下内容替换一个字母。 (以'loveable'为例)
DECLARE @Word varchar(8) = 'lovable';
DECLARE @ReplaceChar varchar(1);
SET @ReplaceChar = SUBSTRING(@Word,PATINDEX('[a-z][abeilost]',@Word)+1,1);
SET @ReplaceChar =
(SELECT CASE @ReplaceChar
WHEN 'a' THEN '@'
WHEN 'b' THEN '8'
WHEN 'e' THEN '3'
WHEN 'i' THEN '!'
WHEN 'l' THEN '1'
WHEN 'o' THEN '0'
WHEN 's' THEN '$'
WHEN 't' THEN '+'
END
);
SET @Word = STUFF(@Word,PATINDEX('[a-z][abeilost]',@Word)+1,1,@ReplaceChar);
据我了解,PATINDEX
应该找到第一个任意字母后跟匹配字母字符串的起始位置,并且 SUBSTRING
/STUFF
在收集或替换之前明确地将 1 添加到该数字,所以我永远不应该将 'lovable' 更改为 '1oveable'...但这就是我得到的。我错过了什么?
阐明预期结果:
Input
Output
loveable
l0veable
give
g1ve
shelter
sh3lter
grams
gr@ms
phrygian
phryg!an
SELECT PATINDEX('[a-z][abeilost]', @Word)
返回的是0。根据documentation 0表示没有找到。找不到的原因是您的搜索条件仅适用于 2 个字符,第一个是匹配 [a-z]
的单个字符,第二个是匹配 [abeilost]
的单个字符。如果您想允许更多字符,则需要扩展搜索表达式,例如
SELECT PATINDEX('[a-z][abeilost]%', @Word)
虽然我认为这不是你想要的,因为我想你想重复指定的字符任意次数,这在 PATINDEX
.
中是不可能的
在我们在上面的评论中讨论之后,我建议采用这种方法:
DECLARE @Word varchar(8) = 'truth';
DECLARE @toBeReplaced VARCHAR(10)='abeilost';
DECLARE @replaceWith VARCHAR(10)='@83!10$+';
DECLARE @position INT=PATINDEX(CONCAT('%[',@toBeReplaced,']%'),SUBSTRING(@word,2,8000))+1;
SELECT STUFF(@word,@position,1,TRANSLATE(SUBSTRING(@word,@position,1),@toBeReplaced,@replaceWith));
简而言之:
- 我们定义您的翻译参数。
- 我们使用第一个字符
PATINDEX()
后面找到位置。
- 现在我们可以使用
STUFF()
将给定位置的一个字符替换为它的翻译。
下一次:如果您提供了一些具有预期结果的示例,将会有很大帮助。
更新
在表格结果中使用它,您可以避免声明的变量并执行此操作 inline:
DECLARE @WordTable TABLE(SomeText varchar(8));
INSERT INTO @WordTable VALUES('truth'),('loveable');
DECLARE @toBeReplaced VARCHAR(10)='abeilost';
DECLARE @replaceWith VARCHAR(10)='@83!10$+';
--新查询
SELECT STUFF(wt.SomeText,pos,1,TRANSLATE(SUBSTRING(wt.SomeText,pos,1),@toBeReplaced,@replaceWith))
FROM @WordTable wt
CROSS APPLY(SELECT PATINDEX(CONCAT('%[',@toBeReplaced,']%'),SUBSTRING(wt.SomeText,2,8000))+1) A(pos);
我正在尝试部分 'leet-ify' 一个词,方法是从一组预定义的可替换字符中取出一个字符,并将其替换为类似于字母的 number/special 字符更换。不过我不想替换第一个字符。
早些时候我得到一个词,我确保在可替换字母集中的第一个字母之后至少有一个字母,并将其放入 @Word
变量中。然后我使用以下内容替换一个字母。 (以'loveable'为例)
DECLARE @Word varchar(8) = 'lovable';
DECLARE @ReplaceChar varchar(1);
SET @ReplaceChar = SUBSTRING(@Word,PATINDEX('[a-z][abeilost]',@Word)+1,1);
SET @ReplaceChar =
(SELECT CASE @ReplaceChar
WHEN 'a' THEN '@'
WHEN 'b' THEN '8'
WHEN 'e' THEN '3'
WHEN 'i' THEN '!'
WHEN 'l' THEN '1'
WHEN 'o' THEN '0'
WHEN 's' THEN '$'
WHEN 't' THEN '+'
END
);
SET @Word = STUFF(@Word,PATINDEX('[a-z][abeilost]',@Word)+1,1,@ReplaceChar);
据我了解,PATINDEX
应该找到第一个任意字母后跟匹配字母字符串的起始位置,并且 SUBSTRING
/STUFF
在收集或替换之前明确地将 1 添加到该数字,所以我永远不应该将 'lovable' 更改为 '1oveable'...但这就是我得到的。我错过了什么?
阐明预期结果:
Input | Output |
---|---|
loveable | l0veable |
give | g1ve |
shelter | sh3lter |
grams | gr@ms |
phrygian | phryg!an |
SELECT PATINDEX('[a-z][abeilost]', @Word)
返回的是0。根据documentation 0表示没有找到。找不到的原因是您的搜索条件仅适用于 2 个字符,第一个是匹配 [a-z]
的单个字符,第二个是匹配 [abeilost]
的单个字符。如果您想允许更多字符,则需要扩展搜索表达式,例如
SELECT PATINDEX('[a-z][abeilost]%', @Word)
虽然我认为这不是你想要的,因为我想你想重复指定的字符任意次数,这在 PATINDEX
.
在我们在上面的评论中讨论之后,我建议采用这种方法:
DECLARE @Word varchar(8) = 'truth';
DECLARE @toBeReplaced VARCHAR(10)='abeilost';
DECLARE @replaceWith VARCHAR(10)='@83!10$+';
DECLARE @position INT=PATINDEX(CONCAT('%[',@toBeReplaced,']%'),SUBSTRING(@word,2,8000))+1;
SELECT STUFF(@word,@position,1,TRANSLATE(SUBSTRING(@word,@position,1),@toBeReplaced,@replaceWith));
简而言之:
- 我们定义您的翻译参数。
- 我们使用第一个字符
PATINDEX()
后面找到位置。 - 现在我们可以使用
STUFF()
将给定位置的一个字符替换为它的翻译。
下一次:如果您提供了一些具有预期结果的示例,将会有很大帮助。
更新
在表格结果中使用它,您可以避免声明的变量并执行此操作 inline:
DECLARE @WordTable TABLE(SomeText varchar(8));
INSERT INTO @WordTable VALUES('truth'),('loveable');
DECLARE @toBeReplaced VARCHAR(10)='abeilost';
DECLARE @replaceWith VARCHAR(10)='@83!10$+';
--新查询
SELECT STUFF(wt.SomeText,pos,1,TRANSLATE(SUBSTRING(wt.SomeText,pos,1),@toBeReplaced,@replaceWith))
FROM @WordTable wt
CROSS APPLY(SELECT PATINDEX(CONCAT('%[',@toBeReplaced,']%'),SUBSTRING(wt.SomeText,2,8000))+1) A(pos);