如果字符出现多次,如何从已知字符之间的字符串中提取文本

时间:2019-05-15 05:13:36

标签: sql-server tsql

我有文字,例如包含#(sharp)字符。字符串包含参数。参数以#开头,以#结束。

declare @TEXT varchar(200) = 'Dear #NAMEOFGUEST# , we glad to see youSOMEHOTEL tomorrow.' 
declare @scanChar char(1)='#'


select
    SUBSTRING(@TEXT, CHARINDEX(@scanChar, @TEXT) + 1, (((LEN(@TEXT)) - CHARINDEX(@scanChar, REVERSE(@TEXT))) - CHARINDEX(@scanChar, @TEXT)))

返回:

NAMEOFGUEST

这是正确的结果。

当字符串仅包含一个参数#NAMEOFGUEST#时,它将起作用。如果将 SOMEHOTEL 添加到#中,则#SOMEHOTEL#的结果不是我们想要的。

 declare @TEXT varchar(200) = 'Dear #NAMEOFGUEST# , we glad to see you #SOMEHOTEL# tomorrow.' 
 declare @scanChar char(1)='#'

返回:

 NAMEOFGUEST# , we glad to see you #SOMEHOTEL

我想要与以前相同的结果,仅像 NAMEOFGUEST

2 个答案:

答案 0 :(得分:3)

使用CHARINDEX(@FindString, @PrintData, CHARINDEX(@FindString, @PrintData) + 1),您可以找到#的第二次出现,然后根据此结果可以完成剩余的计算。

以下查询将起作用。

DECLARE @PrintData AS VARCHAR (200) = 'Dear #NAMEOFGUEST# , we glad to see you #SOMEHOTEL# tomorrow.';
DECLARE @FindString AS CHAR (1) = '#';
DECLARE @LenFindString AS INT = LEN(@FindString);

SELECT SUBSTRING(@PrintData, 
 CHARINDEX(@FindString, @PrintData) + @LenFindString, 
 CHARINDEX(@FindString, @PrintData, CHARINDEX(@FindString, @PrintData) + 1) - (CHARINDEX(@FindString, @PrintData) + @LenFindString)
);     

Demo on db<>fiddle

答案 1 :(得分:0)

您可以使用如下递归方法:

一个模型表,用于模拟面向集合的场景

declare @tbl TABLE(ID INT IDENTITY, SomeComment VARCHAR(100),SomeString varchar(200));
INSERT INTO @tbl VALUES('3 Terms','Dear #NAMEOFGUEST# , we glad to see you #SOMEHOTEL# tomorrow. And even #AThirdOne# is here.')
                      ,('1 Term','Dear #NAMEOFGUEST# , we glad to see you soon.') 
                      ,('No Term','Dear Guest, nice to see you.')
                      ,('invalid 1','Dear Guest, nice to #see you.')
                      ,('invalid ?','Dear #Guest, nice# to see you.');
declare @scanChar char(1)='#';

-查询

WITH recCTE AS
(
    SELECT t.ID
          ,t.SomeComment
          ,t.SomeString AS TextToWork
          ,1 AS TermIndex
          ,D.*
    FROM @tbl t
    OUTER APPLY(SELECT CHARINDEX(@scanChar,t.SomeString)) A(StartingAt)
    OUTER APPLY(SELECT CHARINDEX(@scanChar,t.SomeString,A.StartingAt+1)) B(EndingAt)
    OUTER APPLY(SELECT CASE WHEN A.StartingAt>0 AND B.EndingAt >0 THEN SUBSTRING(t.SomeString,A.StartingAt+1,B.EndingAt- A.StartingAt-1) END) C(TermCandidate)
    OUTER APPLY(SELECT A.StartingAt,B.EndingAt,C.TermCandidate,SUBSTRING(t.SomeString,B.EndingAt+1,1000) AS RestString) D

    UNION ALL

    SELECT t.ID
          ,t.SomeComment
          ,t.RestString 
          ,t.TermIndex+1
          ,D.*
    FROM recCTE t
    OUTER APPLY(SELECT CHARINDEX(@scanChar,t.RestString)) A(StartingAt)
    OUTER APPLY(SELECT CHARINDEX(@scanChar,t.RestString,A.StartingAt+1)) B(EndingAt)
    OUTER APPLY(SELECT CASE WHEN A.StartingAt>0 AND B.EndingAt >0 THEN SUBSTRING(t.RestString,A.StartingAt+1,B.EndingAt- A.StartingAt-1) END) C(TermCandidate)
    OUTER APPLY(SELECT A.StartingAt,B.EndingAt,C.TermCandidate,SUBSTRING(t.RestString,B.EndingAt+1,1000) AS RestString) D
    WHERE (LEN(t.RestString) - LEN(REPLACE(t.RestString,@scanChar,'')))%2=0 AND CHARINDEX(@scanChar,t.RestString)>0
)
SELECT ID
      ,SomeComment
      ,TermIndex
      --this will exclude "Guest, nice" due to the blank
      ,CASE WHEN CHARINDEX(' ',TermCandidate)>0 THEN NULL ELSE TermCandidate END AS Term 
FROM recCTE
ORDER BY ID,TermIndex;

结果

+----+-------------+-----------+-------------+
| ID | SomeComment | TermIndex | Term        |
+----+-------------+-----------+-------------+
| 1  | 3 Terms     | 1         | NAMEOFGUEST |
+----+-------------+-----------+-------------+
| 1  | 3 Terms     | 2         | SOMEHOTEL   |
+----+-------------+-----------+-------------+
| 1  | 3 Terms     | 3         | AThirdOne   |
+----+-------------+-----------+-------------+
| 2  | 1 Term      | 1         | NAMEOFGUEST |
+----+-------------+-----------+-------------+
| 3  | No Term     | 1         | NULL        |
+----+-------------+-----------+-------------+
| 4  | invalid 1   | 1         | NULL        |
+----+-------------+-----------+-------------+
| 5  | invalid ?   | 1         | NULL        |
+----+-------------+-----------+-------------+