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);