如何将 mailto 放在文本字符串中的电子邮件地址周围

How to put mailto around email addresses in text string

我想弄清楚如何能够 select/find 并格式化一段文本中包含的每个电子邮件地址。

示例字符串:

Notification: Organizer must notify at least 30 days prior to the event. Provide the event information, including: day of contact information, location, date, schedule, activities, etc. Paul T. Hall – paulhall@email.com - Mikel Zubizarreta – mikelzubizarreta@email.com

字符串的输出应该是:

Notification: Organizer must notify at least 30 days prior to the event. Provide the event information, including: day of contact information, location, date, schedule, activities, etc. Paul T. Hall – <a href='mailto:paulhall@email.com'> - paulhall@email.com</a> - Mikel Zubizarreta – <a href='mailto:mikelzubizarreta@email.com'>mikelzubizarreta@email.com</a>

这是我的尝试:

内 select:

,   CASE 
        WHEN CHARINDEX('@',CONDITION) > 0 THEN 
            REPLACE(CONDITION, dbo.FN_GET_EMAIL_FROM_STRING(CONDITION), '<a href=''mailto:' + dbo.FN_GET_EMAIL_FROM_STRING(CONDITION) + '''>' + dbo.FN_GET_EMAIL_FROM_STRING(CONDITION) + '</a>')
        ELSE CONDITION
    END [CONDITION]

dbo.FN_GET_EMAIL_FROM_STRING(条件)的内容:

ALTER FUNCTION [dbo].[FN_GET_EMAIL_FROM_STRING]
(
    @TextContainingEmail VARCHAR(1000)
)
RETURNS VARCHAR(1000)
AS
    BEGIN

        DECLARE @retval VARCHAR(1000);

        SELECT TOP 
            1 @retval = Items 
        FROM 
            dbo.FN_SPLIT_STRING(@TextContainingEmail, '')
        WHERE 
            Items LIKE '%@%';            

         RETURN @retval;         

    END;

内容:FN_SPLIT_STRING(@TextContainingEmail, '')

    ALTER FUNCTION [dbo].[FN_SPLIT_STRING]
    (
        @STRING NVARCHAR(4000)
    ,   @Delimiter CHAR(1)
    )

    RETURNS @Results TABLE(Items NVARCHAR(4000))

    AS
         BEGIN

             DECLARE @INDEX INT;
             DECLARE @SLICE NVARCHAR(4000);

             -- HAVE TO SET TO 1 SO IT DOESNT EQUAL ZERO FIRST TIME IN LOOP
             SELECT @INDEX = 1;

             IF @STRING IS NULL
                 RETURN;
             WHILE @INDEX != 0
                 BEGIN 
                     -- GET THE INDEX OF THE FIRST OCCURENCE OF THE SPLIT CHARACTER
                     SELECT 
                       @INDEX = CHARINDEX(@Delimiter, LTRIM(RTRIM(@STRING)));
                     -- NOW PUSH EVERYTHING TO THE LEFT OF IT INTO THE SLICE VARIABLE
                     IF @INDEX != 0
                         SELECT 
                           @SLICE = LEFT(@STRING, @INDEX - 1);
                         ELSE
                         SELECT 
                           @SLICE = @STRING;
                     -- PUT THE ITEM INTO THE RESULTS SET
                     INSERT INTO @Results
                     (
                       Items
                     )
                     VALUES(@SLICE);
                     -- CHOP THE ITEM REMOVED OFF THE MAIN STRING
                     SELECT 
                       @STRING = REPLACE(RIGHT(@STRING, LEN(@STRING) - @INDEX), ',', '');
                     -- BREAK OUT IF WE ARE DONE
                     IF LEN(@STRING) = 0
                         BREAK;
                 END;
             RETURN;
         END;

但是我在此 post 顶部用作示例的字符串的输出最终看起来像这样:

Notification: Organizer must notify at least 30 days prior to the event. Provide the event information, including: day of contact information, location, date, schedule, activities, etc. Paul T. Hall – <a href='mailto:paulhall@email.com'>paulhall@email.com</a> - Mikel Zubizarreta – mikelzubizarreta@email.com

如您所见,它有点管用,但它只将 'mailto' 标记广告到第一个电子邮件地址,而不是第二个。

此解决方案使用 Eirikur Eiriksson 基于 Jeff Moden 的原始函数创建的拆分器函数。这个函数的完整解释可以在here中找到。 我只是复制该函数的代码。

CREATE FUNCTION [dbo].[DelimitedSplit8K_LEAD]
--===== Define I/O parameters
        (@pString VARCHAR(8000), @pDelimiter CHAR(1))
RETURNS TABLE WITH SCHEMABINDING AS
 RETURN
--===== "Inline" CTE Driven "Tally Table” produces values from 0 up to 10,000...
     -- enough to cover VARCHAR(8000)
 WITH E1(N) AS (
                 SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
                 SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
                 SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
                ),                          --10E+1 or 10 rows
       E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows
       E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max
 cteTally(N) AS (--==== This provides the "zero base" and limits the number of rows right up front
                     -- for both a performance gain and prevention of accidental "overruns"
                 SELECT 0 UNION ALL
                 SELECT TOP (DATALENGTH(ISNULL(@pString,1))) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4
                ),
cteStart(N1) AS (--==== This returns N+1 (starting position of each "element" just once for each delimiter)
                 SELECT t.N+1
                   FROM cteTally t
                  WHERE (SUBSTRING(@pString,t.N,1) = @pDelimiter OR t.N = 0) 
                )
--===== Do the actual split. The ISNULL/NULLIF combo handles the length for the final element when no delimiter is found.
 SELECT ItemNumber = ROW_NUMBER() OVER(ORDER BY s.N1),
        Item = SUBSTRING(@pString,s.N1,ISNULL(NULLIF((LEAD(s.N1,1,1) OVER (ORDER BY s.N1) - 1),0)-s.N1,8000))
   FROM cteStart s
;
GO

这样我们就可以独立识别电子邮件地址并使用 FOR XML.

再次连接字符串
CREATE TABLE #SampleData(
    String  varchar(8000)
)
INSERT INTO #SampleData VALUES('Notification: Organizer must notify at least 30 days prior to the event. Provide the event information, including: day of contact information, location, date, schedule, activities, etc. Paul T. Hall – paulhall@email.com - Mikel Zubizarreta – mikelzubizarreta@email.com')

SELECT STUFF(( SELECT ' ' + CASE WHEN s.Item LIKE '_%@_%._%' THEN '<a href=''mailto:' + s.Item + '''>' + s.Item + '</a>'
                            ELSE s.Item END
            FROM dbo.DelimitedSplit8K_LEAD( d.String, ' ') s
            ORDER BY s.ItemNumber
            FOR XML PATH(''), TYPE).value('./text()[1]', 'varchar(max)'), 1, 1, '')
FROM #SampleData d