我的RTF解析器需要处理两种rtf文件(每个程序执行一个文件):rtf文件保存自Word和rtf文件,由COTS报告生成器实用程序创建。每个rtf都有效,但不同。我的解析器使用正则表达式模式来检测,提取和处理两种类型的rtf文件中的各种rtf元素。
我决定在两个字典中实现rtf正则表达式模式列表,一个用于Word rtf文件所需的rtf正则表达式模式,另一个用于COTS实用程序rtf文件所需的rtf正则表达式模式。在运行时,我的解析器检测正在处理哪种类型的rtf文件(Word rtf包括rtf元素//schemas.microsoft.com/office/word
而COTS rtf没有),然后从appopriate字典中获取所需的正则表达式模式。
为了在编写代码时简化引用模式的任务,我实现了一个枚举,其中每个枚举值代表一个特定的正则表达式模式。为了简化使模式与其对应的枚举保持同步的任务,我将正则表达式模式实现为here-string
,其中每一行都是csv组合:{enum name}, {word rtf regex pattern}, {cots rtf regex pattern}
。然后,在将模式加载到其字典中的运行时,我从csv获取枚举的int值并使用它来创建字典键。
这使得编写代码更容易,但我不确定它是实现和引用rtf表达式的最佳方法。有没有更好的办法?
示例代码:
public enum Rex {FOO, BAR};
string ex = @"FOO, word rtf regex pattern for FOO, cots rtf regex pattern for FOO
BAR, word rtf regex pattern for BAR, cots rtf regex pattern for BAR
";
我加载这样的字典:
using (StringReader reader = new StringReader(ex))
{
string line;
while ((line = reader.ReadLine()) != null)
{
string[] splitLine = line.Split(',');
int enumIntValue = (int)(Rex)Enum.Parse(typeof(Rex), splitLine[0].Trim());
ObjWordRtfDict.Add(enumIntValue, line.Split(',')[1].Trim());
ObjRtfDict.Add(enumIntValue, line.Split(',')[2].Trim());
}
}
然后,在运行时,我根据解析器检测到的rtf文件的类型访问ObjWordRtfDict或ObjRtfDict。
string regExPattFoo = ObjRegExExpr.GetRegExPattern(ClsRegExExpr.Rex.FOO);
public string GetRegExPattern(Rex patternIndex)
{
string regExPattern = "";
if (isWordRtf)
{
ObjWordRtfDict.TryGetValue((int)patternIndex, out regExPattern);
}
else
{
ObjRtfDict.TryGetValue((int)patternIndex, out regExPattern);
}
return regExPattern;
}
修改了基于Asif建议的新代码
我保留了枚举模式名称,因此编译器可以检查对模式名称的引用
示例csv文件作为嵌入式资源包含在内
SECT,^\\pard.*\{\\rtlch.*\\sect\s\}, ^\\pard.*\\sect\s\}
HORZ_LINE2, \{\\pict.*\\pngblip, TBD
用法示例
string sectPattern = ObjRegExExpr.GetRegExPattern(ClsRegExPatterns.Names.SECT);
ClsRegExPatterns类
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
namespace foo
{
public class ClsRegExPatterns
{
readonly bool isWordRtf = false;
List<ClsPattern> objPatternList;
public enum Names { SECT, HORZ_LINE2 };
public class ClsPattern
{
public string Name { get; set; }
public string WordRtfRegex { get; set; }
public string COTSRtfRegex { get; set; }
}
public ClsRegExPatterns(StringBuilder rawRtfTextFromFile)
{
// determine if input file is Word rtf or not Word rtf
if ((Regex.Matches(rawRtfTextFromFile.ToString(), "//schemas.microsoft.com/office/word", RegexOptions.IgnoreCase)).Count == 1)
{
isWordRtf = true;
}
//read patterns from embedded content csv file
string patternsAsCsv = new StreamReader((Assembly.GetExecutingAssembly()).GetManifestResourceStream("eLabBannerLineTool.Packages.patterns.csv")).ReadToEnd();
//create list to hold patterns
objPatternList = new List<ClsPattern>();
//load pattern list
using (StringReader reader = new StringReader(patternsAsCsv))
{
string line;
while ((line = reader.ReadLine()) != null)
{
string[] splitLine = line.Split(',');
ClsPattern objPattern = new ClsPattern
{
Name = splitLine[0].Trim(),
WordRtfRegex = splitLine[1].Trim(),
COTSRtfRegex = splitLine[2].Trim()
};
objPatternList.Add(objPattern);
}
}
}
public string GetRegExPattern(Names patternIndex)
{
string regExPattern = "";
string patternName = patternIndex.ToString();
if (isWordRtf)
{
regExPattern = objPatternList.SingleOrDefault(x => x.Name == patternName)?.WordRtfRegex;
}
else
{
regExPattern = objPatternList.SingleOrDefault(x => x.Name == patternName)?.COTSRtfRegex;
}
return regExPattern;
}
}
}
如果我理解你的问题陈述;我宁愿喜欢下面这样的东西。
创建一个名为RtfProcessor的类
public class RtfProcessor
{
public string Name { get; set; }
public string WordRtfRegex { get; set; }
public string COTSRtfRegex { get; set; }
void ProcessFile()
{
throw new NotImplementedException();
}
}
其中name表示FOO或BAR等。您可以维护此类文件的列表,并继续填充csv文件,如下所示
List<RtfProcessor> fileProcessors = new List<RtfProcessor>();
using (StringReader reader = new StringReader(ex))
{
string line;
while ((line = reader.ReadLine()) != null)
{
string[] splitLine = line.Split(',');
RtfProcessor rtfProcessor = new RtfProcessor();
rtfProcessor.Name = splitLine[0].Trim();
rtfProcessor.WordRtfRegex = line.Split(',')[1].Trim();
rtfProcessor.WordRtfRegex = line.Split(',')[2].Trim();
fileProcessors.Add(rtfProcessor);
}
}
并检索FOO或BAR的正则表达式模式
// to get the regex parrtern for FOO you can use
fileProcessors.SingleOrDefault(x => x.Name == "FOO")?.WordRtfRegex;
希望这可以帮助。