我正在尝试找到一种灵活的方式来解析电子邮件内容.下面是我正在使用的虚拟电子邮件文本的示例.如果可能的话,我也想避免使用正则表达式.然而,在解决问题的过程中,我开始认为这是不可避免的.请注意,这只是完整电子邮件的一个小虚拟子集.我需要的是将每个字段(例如,票号,手机)解析为各自的数据类型.最后,电子邮件中不保证某些字段存在(您将在下面显示的当前解决方案中看到为什么这是一个问题).
Header Code:EMERGENCY
Ticket No: 123456789 Seq. No: 2
Update of:
Original Call Date: 01/02/2011 Time: 11:17:03 AM OP: 1102
Second Call Date: 01/02/2011 Time: 12:11:00 AM OP:
Company: COMPANY NAME
Contact: CONTACT NAME Contact Phone: (111)111-1111
Secondary Contact: SECONDARY CONTACT
Alternate Contact: Altern. Phone:
Best Time to Call: AFTER 4:30P Fax No: (111)111-1111
Cell Phone: Pager No:
Caller Address: 330 FOO
FOO AVENUE 123
Run Code Online (Sandbox Code Playgroud)
对于这个简单的例子,我成功地能够使用下面的函数解析大多数字段.
private T BetweenOperation<T>(string emailBody, string start, string end)
{
var culture = StringComparison.InvariantCulture;
int startIndex =
emailBody.IndexOf(start, culture) + start.Length;
int endIndex =
emailBody.IndexOf(end, culture);
int length = endIndex - startIndex;
if (length < 0) return default(T);
return (T)Convert.ChangeType(
emailBody.Substring(startIndex, length).Trim(),
typeof(T));
}
Run Code Online (Sandbox Code Playgroud)
从本质上讲,我的想法是我可以解析两个字段之间的内容.例如,我可以通过执行标头代码
// returns "EMERGENCY"
BetweenOperation<string>("email content", "Header Code:", "Ticket No:")
Run Code Online (Sandbox Code Playgroud)
然而,这种方法存在许多缺陷.一个很大的缺陷是该end领域并不总是存在.正如您所看到的,有一些类似的键具有相同的关键字,无法解析得恰到好处,例如"联系人"和"次要联系人".这会导致解析器获取太多信息.此外,如果我的结束字段不存在,我将得到一些不可预测的结果.最后,我可以解析整行,然后将其传递给BetweenOperation<T>使用它.
private string LineOperation(string startWithCriteria)
{
string[] emailLines = EmailBody.Split(new[] { '\n' });
return
emailLines.Where(emailLine => emailLine.StartsWith(startWithCriteria))
.FirstOrDefault();
}
Run Code Online (Sandbox Code Playgroud)
我们会LineOperation在某些情况下使用字段名称不唯一(例如时间)并将结果提供给BetweenOperation<T>.
如何根据键解析上面显示的内容.例如,键是"标题代码"和"手机".请注意,我不认为基于制表符的空格进行解析,因为某些字段可能是多行(例如,来电者地址)或根本不包含任何值(例如Altern Phone).
谢谢.
解决该问题的一种方法是首先在整个文本中搜索您的键的出现情况。也就是说,构建一个如下所示的数组:
"Header Code:",1
"Contact Phone:",233
"Cell Phone:",-1 // not there
Run Code Online (Sandbox Code Playgroud)
如果您按位置对该数组进行排序,那么您就知道在哪里查找内容。也就是说,您将知道每个字段后面跟着哪些字段。
您必须对重复项执行某些操作(即调用日期中的“时间:”和“时间:”)。您必须解决“联系人:”和“第二联系人:”的问题,尽管这应该很容易。
如果您使用标准字符串操作(即IndexOf)来执行此操作,效率会有些低,因为您必须在整个文本中搜索每个字符串的所有出现位置。很难说这对你来说是否是一个问题。取决于你需要做多少这些。
如果这成为一个问题,您可能需要构建一个 Aho-Corasick 字符串匹配器或类似的东西。或者你可以构建一个大的丑陋的正则表达式:
"(Header Code:)|(Contact Phone:)|(Cell Phone)"...等等。可能有命名捕获,这样您就知道您正在捕获什么。它应该工作得相当好,尽管它可能很难维护。