【问题标题】:Split String With Multiple Delimiters and Retain Delimiters使用多个分隔符拆分字符串并保留分隔符
【发布时间】:2025-12-21 02:50:09
【问题描述】:

我需要将字符串拆分为特定单词边界的行。问题是我需要维护触发拆分的特定单词边界,因为稍后我想重新组合行并查看分隔符。我正在更新一个看起来像这样的现有函数:

DECLARE @Input VARCHAR(8000) = 'AC/DC, The Quick, Brown Fox'
DECLARE @Delimiters varchar(100) = '%[ ,-/]%'

;WITH 
    [Elements] AS
    (
        SELECT
            1 AS Position
            , 1 AS StartOffset
            , PATINDEX(@Delimiters, @Input) - 1 AS EndOffset
            , @Input AS Input
            , SUBSTRING(@Input, 1, ISNULL(NULLIF(PATINDEX(@Delimiters, @Input), 0) - 1, 8000)) AS Word
        UNION ALL
        SELECT 
            Position + 1 AS Position
            , EndOffset + 2 AS StartOffset
            , EndOffset + ISNULL(NULLIF(PATINDEX(@Delimiters, SUBSTRING(Input, EndOffset + 2, 8000)), 0), LEN(@Input) - EndOffset) AS EndOffset
            , Input
            , SUBSTRING(Input, EndOffset + 2, ISNULL(NULLIF(PATINDEX(@Delimiters, SUBSTRING(Input, EndOffset + 2, 8000)), 0) - 1, 8000)) AS Word
        FROM 
            [Elements]
        WHERE 
            EndOffset BETWEEN 1 AND LEN(@Input) - 1
    )
SELECT
    *
FROM
    [Elements]

给我:

+----------+-------------+-----------+-----------------------------+-------+
| Position | StartOffset | EndOffset |            Input            | Word  |
+----------+-------------+-----------+-----------------------------+-------+
|        1 |           1 |         2 | AC/DC, The Quick, Brown Fox | AC    |
|        2 |           4 |         5 | AC/DC, The Quick, Brown Fox | DC    |
|        3 |           7 |         6 | AC/DC, The Quick, Brown Fox |       |
|        4 |           8 |        10 | AC/DC, The Quick, Brown Fox | The   |
|        5 |          12 |        16 | AC/DC, The Quick, Brown Fox | Quick |
|        6 |          18 |        17 | AC/DC, The Quick, Brown Fox |       |
|        7 |          19 |        23 | AC/DC, The Quick, Brown Fox | Brown |
|        8 |          25 |        27 | AC/DC, The Quick, Brown Fox | Fox   |
+----------+-------------+-----------+-----------------------------+-------+

这很好地分解了它,但从结果集中省略了“/”和“,”行。我确实有一个可以碰到的数字表,而且我对如何实现这一点非常灵活。

我可以通过循环蛮力通过它,但这似乎太野蛮了。

【问题讨论】:

  • 请不要朝这个方向吐痰……
  • 您的拆分逻辑不能很好地处理两个分隔符。您最好将整个事情分解(您可以使用数字表),检查每个字符是否是分隔符,然后构建类似于当前逻辑的单词。
  • @JNK 你能提供一个使用数字表对已知分隔符列表进行拆分的示例吗?
  • @JohnHurrell 他们到处都是(搜索字符串拆分 SQL 数字表),但基本思想是使用数字表有效地索引到字符串的每个字符。
  • @JNK:无论如何,谢谢,但我所知道的所有示例都使用数字表对单个逗号分隔符拆分字符串。我现在正在通过使用一些逻辑来修改我需要做的事情,其中​​字符在一个位置 NOT LIKE '[a-z]' 希望我可以避免必须指定大量的分隔符。

标签: sql-server


【解决方案1】:

好吧,你已经接近了,你只需要修改“拆分”是否在分隔符上的逻辑。代码变得丑陋,但您不必强行使用它。如果我真的努力,我也许可以让它“更漂亮”。我只是在快速构建您创建的内容。

DECLARE @Input VARCHAR(8000) = ',AC/DC,,The Quick, Brown Fox-Hound'
DECLARE @Delimiters varchar(100) = '%[ ,-/]%'

;WITH 
    [Elements] AS
    (
        SELECT
            1 AS Position
            , 1 AS StartOffset
            , PATINDEX(@Delimiters, @Input) - 1 + case when  PATINDEX(@Delimiters, Left(@Input,1)) = 1 then 1 else 0 end AS EndOffset
            , @Input AS Input
            , SUBSTRING(@Input, 1, ISNULL(NULLIF(PATINDEX(@Delimiters, @Input), 0) - 1 +case when  PATINDEX(@Delimiters, Left(@Input,1)) = 1 then 1 else 0 end, 8000)) AS Word
        UNION ALL
        SELECT 
            Position +1 AS Position
            , EndOffset + 1 AS StartOffset
            , EndOffset + ISNULL(NULLIF(PATINDEX(@Delimiters, SUBSTRING(Input, EndOffset+1 , 8000)), 0) -  case when  PATINDEX(@Delimiters, SUBSTRING(Input, EndOffset+1 , 8000)) = 1 then 0 else 1 end  ,datalength(Input)-endoffset) EndOffset
            , Input
            , SUBSTRING(Input, EndOffset+ 1 , ISNULL(NULLIF(PATINDEX(@Delimiters, SUBSTRING(Input, EndOffset+1 , 8000)), 0) -  case when  PATINDEX(@Delimiters, SUBSTRING(Input, EndOffset+1 , 8000)) = 1 then 0 else 1 end  ,datalength(Input)-endoffset)) AS Word
        FROM 
            [Elements]
        WHERE 
            EndOffset BETWEEN 1 AND datalength(@Input)-1 
    )
SELECT
    *
FROM
    [Elements]

【讨论】:

  • 要求发生了变化,因此我们无法使用此解决方案,但它可以正常工作并且可以按预期工作,因此我将其标记为已回答。感谢您的代码。