我正在尝试解析将定期发送的电子邮件文件,以获取其中包含的数据。我们计划设置cfmail,以使CF Admin框中的电子邮件每分钟运行一次。
电子邮件中的数据由名称,代号,地址,描述等组成,并将具有一致的标签,因此我们正在考虑对每个数据字段执行循环或查找功能。会是一个好的开始吗?
以下是电子邮件数据的示例:
INCIDENT#12345
长期系统号C12345
报告:08:39:34 05/20/19性质:FD NEED地址:12345 N TEST LN 城市:Testville
响应单位:T12
十字路口:N个测试LN和W TEST LN的交叉点
Lat = 39.587453 Lon = -86.485021
评论:这是一个测试帖子。请忽略
这是数据实际外观的图片:
所以我们想提取以下内容:
任何反馈或建议将不胜感激!
答案 0 :(得分:1)
有人发布了此消息,但显然已将其删除。无论是谁,我都非常感谢您,因为它运行得很好!!!!
功能如下:
<!---CREATE FUNCTION [tvf-Str-Extract] (@String varchar(max),@Delimiter1
varchar(100),@Delimiter2 varchar(100))
Returns Table
As
Return (
with cte1(N) as (Select 1 From (values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1))
N(N)),
cte2(N) as (Select Top (IsNull(DataLength(@String),0)) Row_Number() over (Order By
(Select NULL)) From (Select N=1 From cte1 N1,cte1 N2,cte1 N3,cte1 N4,cte1 N5,cte1 N6) A
),
cte3(N) as (Select 1 Union All Select t.N+DataLength(@Delimiter1) From cte2 t
Where Substring(@String,t.N,DataLength(@Delimiter1)) = @Delimiter1),
cte4(N,L) as (Select S.N,IsNull(NullIf(CharIndex(@Delimiter1,@String,s.N),0)-
S.N,8000) From cte3 S)
Select RetSeq = Row_Number() over (Order By N)
,RetPos = N
,RetVal = left(RetVal,charindex(@Delimiter2,RetVal)-1)
From ( Select *,RetVal = Substring(@String, N, L) From cte4 ) A
Where charindex(@Delimiter2,RetVal)>1
)
这是起作用的CF代码:
<cfquery name="body" datasource="#Application.dsn#">
Declare @S varchar(max) ='
INCIDENT 12345
LONG TERM SYS C12345
REPORTED: 08:39:34 05/20/19 Nature: FD NEED Address: 12345 N TEST
LN City: Testville
Responding Units: T12
Cross Streets: Intersection of: N Test LN & W TEST LN
Lat= 39.587453 Lon= -86.485021
Comments: This is a test post. Please disregard
'
Select Incident = ltrim(rtrim(B.RetVal))
,LongTerm = ltrim(rtrim(C.RetVal))
,Reported = ltrim(rtrim(D.RetVal))
,Nature = ltrim(rtrim(E.RetVal))
,Address = ltrim(rtrim(F.RetVal))
,City = ltrim(rtrim(G.RetVal))
,RespUnit = ltrim(rtrim(H.RetVal))
,CrossStr = ltrim(rtrim(I.RetVal))
,Comments = ltrim(rtrim(J.RetVal))
From (values (replace(replace(@S,char(10),''),char(13),' ')) )A(S)
Outer Apply [dbo].[tvf-Str-Extract](S,'INCIDENT' ,'LONG
TERM' ) B
Outer Apply [dbo].[tvf-Str-Extract](S,'LONG TERM SYS'
,'REPORTED' ) C
Outer Apply [dbo].[tvf-Str-Extract](S,'REPORTED:' ,'Nature'
) D
Outer Apply [dbo].[tvf-Str-Extract](S,'Nature:'
,'Address' ) E
Outer Apply [dbo].[tvf-Str-Extract](S,'Address:' ,'City'
) F
Outer Apply [dbo].[tvf-Str-Extract](S,'City:'
,'Responding ') G
Outer Apply [dbo].[tvf-Str-Extract](S,'Responding Units:','Cross'
) H
Outer Apply [dbo].[tvf-Str-Extract](S,'Cross Streets:' ,'Lat'
) I
Outer Apply [dbo].[tvf-Str-Extract](S+'|||','Comments:' ,'|||'
) J
</cfquery>
<cfoutput>
B. #body.Incident#<br>
C. #body.LongTerm#<br>
D. #body.Reported#<br>
答案 1 :(得分:0)
SQL往往具有有限的字符串函数,因此它不是解析的最佳工具。如果电子邮件内容始终是该格式的 ,则可以使用纯字符串函数或正则表达式进行解析。但是,后者更灵活。
我怀疑内容实际上确实包含新行,这将使解析变得更简单。但是,如果您希望在两个标签之间搜索内容,则使用正则表达式可以解决问题。
构建一个标签名称数组(仅)。遍历数组,获取一对标签:“当前”和“下一个”。在正则表达式中使用两个值来提取它们之间的文本:
label &"\s*[##:=](.*?)"& nextLabel
/* Explanation: */
label - First label name (example: "Incident")
\s* - Zero or more spaces
[##:=] - Any of these characters: pound sign, colon or equal sign
(.*?) - Group of zero or more characters (non-greedy)
nextLabel - Next label (example: "Long Term Sys")
使用reFindNoCase()获取有关匹配文本的位置和长度的详细信息。然后将这些值与mid()结合使用以提取文本。
请注意,较新的版本,例如ColdFusion 2016+,会自动在名为MATCH
的键下提取文本
较新的CF2016 +语法比较简洁,但是在CF10下可以使用以下内容:
emailBody = "INCIDENT # 12345 ... etc.... ";
labelArray = ["Incident", "Long Term Sys", "Reported", ..., "Comments" ];
for (pos = 1; pos <= arrayLen(labelArray); pos++) {
// get current and next label
hasNext = pos < arrayLen(labelArray);
currLabel = labelArray[ pos ];
nextLabel = (hasNext ? labelArray[ pos+1 ] : "$");
// extract label and value
matches = reFindNoCase( currLabel &"\s*[##:=](.*?)"& nextLabel, emailBody, 1, true);
if (arrayLen(matches.len) >= 2) {
results[ currLabel ] = mid( emailBody, matches.pos[2], matches.len[2]);
}
}
writeDump( results );
结果: