Coldfusion-如何解析和分段电子邮件文件中的数据

时间:2019-05-23 14:25:40

标签: sql-server coldfusion

我正在尝试解析将定期发送的电子邮件文件,以获取其中包含的数据。我们计划设置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

     

评论:这是一个测试帖子。请忽略

这是数据实际外观的图片:

enter image description here

所以我们想提取以下内容:

  1. INCIDENT
  2. 长期系统编号
  3. 已报告
  4. 自然
  5. 地址
  6. 城市
  7. 响应单位
  8. 过马路
  9. 评论

任何反馈或建议将不胜感激!

2 个答案:

答案 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


的键下提取文本 Example of reFindNoCase result in CF 2018

较新的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 );

结果:

Screenshot of parsed results