如何将 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
我想弄清楚如何能够 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