【问题标题】:Replace a recurring word and the character before it替换重复出现的单词及其前面的字符
【发布时间】:2021-07-08 19:02:24
【问题描述】:

我正在使用 SQL Server 尝试替换字符串中每个重复出现的“[BACKSPACE]”和单词 [BACKSPACE] 之前的字符,以模仿退格键的作用。

这是我当前的字符串: "This is a string that I would like to d[BACKSPACE]correct and see if I could make it %[BACKSPACE] cleaner by removing the word and $[BACKSPACE] character before the backspace."

这就是我想说的: "This is a string that I would like to correct and see if I could make it cleaner by removing the word and character before the backspace."

让我更清楚地说明这一点。在上面的示例字符串中,$ 和 % 符号仅用作需要删除的字符示例,因为它们位于我要替换的 [BACKSPACE] 单词之前。

这是另一个之前的例子: The dog likq[BACKSPACE]es it's owner

我想将其编辑为: The dog likes it's owner

最后一个例子是: I am frequesn[BACKSPACE][BACKSPACE]nlt[BACKSPACE][BACKSPACE]tly surprised

我想将其编辑为: I am frequently surprised

【问题讨论】:

  • 支持正则表达式替换的语言在这里会好得多。另外,您说它只删除字符 before,但这仅适用于 'd[BACKSPACE]'。对于%[BACKSPACE]$[BACKSPACE],它还会先删除前导空格。
  • 您的 SQL Server 版本是多少?
  • @YitzhakKhabinsky SQL Server 2008 R2 SP3
  • 根据问题指南,请展示您的尝试并告诉我们您发现了什么(在本网站或其他地方)以及为什么它不能满足您的需求。

标签: sql sql-server tsql string-concatenation


【解决方案1】:

如果没有提供正则表达式替换的 CLR 函数,您能够做到这一点的唯一方法是在 T-SQL 中进行迭代。但是请注意,以下解决方案确实为您提供您要求的结果,但提供您要求的逻辑。您声明要删除之前的字符串和字符,但在您的两种情况下,这不是真的。对于最后 2 个字符串,您分别删除 ' %[BACKSPACE]'' $[BACKSPACE]'(注意前导空格)。

这个前导空格留在这个解决方案中。我不想解决这个问题,因为真正的解决方案是不要为此使用 T-SQL,而是使用支持正则表达式的东西。

我还假设这个字符串来自表中的一列,并且所述表有多行(每行都有不同的字符串值)。

无论如何,解决办法:

WITH rCTE AS(
    SELECT V.YourColumn,
           STUFF(V.YourColumn,CHARINDEX('[BACKSPACE]',V.YourColumn)-1,LEN('[BACKSPACE]')+1,'') AS ReplacedColumn,
           1 AS Iteration
    FROM (VALUES('"This is a string that I would like to d[BACKSPACE]correct and see if I could make it %[BACKSPACE] cleaner by removing the word and $[BACKSPACE] character before the backspace."'))V(YourColumn)
    UNION ALL
    SELECT r.YourColumn,
           STUFF(r.ReplacedColumn,CHARINDEX('[BACKSPACE]',r.ReplacedColumn)-1,LEN('[BACKSPACE]')+1,''),
           r.Iteration + 1
    FROM rCTE r
    WHERE CHARINDEX('[BACKSPACE]',r.ReplacedColumn) > 0)
SELECT TOP (1) WITH TIES
       r.YourColumn,
       r.ReplacedColumn
FROM rCTE r
ORDER BY ROW_NUMBER() OVER (PARTITION BY r.YourColumn ORDER BY r.Iteration DESC);

dB<>fiddle

【讨论】:

  • 这真的很好用!我发现的唯一问题是如果有很多 [BACKSPACE] 标记,然后在遍历字符串后 [BACKSPACE] 之前没有更多字符,即使后面有更多单词,它也会返回为 null。因此,如果输入字符串是'Word[BACKSPACE][BACKSPACE][BACKSPACE][BACKSPACE][BACKSPACE]SecondWord',它将返回为 NULL,因为当它到达第五个退格时,在字符串的开头没有更多的字符可以删除。修改返回为'Word SecondWord' 的最佳方法是什么。基本上忽略第五个 [BACKSPACE]。
  • 这是对目标帖子 @Tom86493 的重大更改。 在收到答案之后,您应该提出一个不改变目标的新问题。
  • 会做的,再次感谢您。我将创建一个新问题。
【解决方案2】:

这是一个应该可以工作的简单 RegEx 模式:

/.\[BACKSPACE\]/g

编辑 我现在无法在我的 chromebook 上对此进行测试,但这似乎应该适用于 LIKE 子句中的 T-SQL

LIKE '_\[BACKSPACE]' ESCAPE '\'

【讨论】:

  • 不会在 T-SQL 中。正如我的回答和评论所述,它不支持正则表达式。
  • LIKE 不会替换字符。 SQL Server 的字符串操作充其量是很差的;它没有模式替换过程。
  • 替换来自正则表达式模式可能会很麻烦,但我将链接有关该主题的其他一些讨论 - stackoverflow.com/questions/38186932/…
  • 是的,该问题中接受的答案是我上面答案的(较慢)变体。
【解决方案3】:

我想看看我是否可以使用传统的计数表方法让它工作而不需要任何递归。

我认为我有一些可行的方法 - 但是递归 cte 版本绝对是一种更清洁的解决方案并且可能性能更好,但是将其作为一种替代的非递归方式投入使用。

/* tally table for use below */
select top 1000 N=Identity(int, 1, 1)
into dbo.Digits
from master.dbo.syscolumns a cross join master.dbo.syscolumns

with w as (
 select seq = Row_Number() over (order by t.N),
 part = Replace(Substring(@string, t.N, CharIndex(Left(@delimiter,1), @string + @delimiter, t.N) - t.N),Stuff(@delimiter,1,1,''),'')
 from Digits t
 where t.N <= DataLength(@string)+1 and Substring(Left(@delimiter,1) + @string, t.N, 1) = Left(@delimiter,1)
),
p as (
    select seq,Iif(Iif(Lead(part) over(order by seq)='' and lag(part) over(order by seq)='',1,0 )=1 ,'', Iif( seq<Max(seq) over() and part !='',Left(part,Len(part)-1),part)) part
    from w
)
select result=(
    select ''+ part
    from p
    where part!=''
    order by seq
    for xml path('')
)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-12-20
    • 1970-01-01
    • 1970-01-01
    • 2014-06-01
    • 2021-08-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-05
    相关资源
    最近更新 更多