[英]C# Template parsing and matching with text file
需要一些想法如何解决这个问题。 我有一个模板文件,用于描述文本文件中的行。 例如:
模板
[%f1%]|[%f2%]|[%f3%]"[%f4%]"[%f5%]"[%f6%]
文本文件
1234|1234567|123"12345"12"123456
现在我需要从文本文件中读取字段。 在模板文件中,字段用[%some name%]
。 另外在模板文件中设置了字段分隔符,在这个例子中有|
和"
。该领域的lenght可以通过不同的文件改变,但分离器将保持不变。什么是模板和模板在文本文件中读取读取的最佳方式?
编辑:文本文件有多行,如下所示:
1234|1234567|123"12345"12"123456"\r\n
1234|field|123"12345"12"asdasd"\r\n
123sd|1234567|123"asdsadf"12"123456"\r\n
45gg|somedata|123"12345"12"somefield"\r\n
编辑2:好的,让我们更难。 某些字段可以包含二进制数据,我知道二进制数据字段的起始位置和结束位置。 我应该能够在模板中标记这些字段,然后解析器将知道该字段是二进制的。 如何解决这个问题呢?
您可以使用正则表达式解析模板。 像这样的表达式将匹配每个字段定义和分隔符:
Match m = Regex.Match(template, @"^(\[%(?<name>.+?)%\](?<separator>.)?)+$")
该匹配将包含两个命名组(名称和分隔符),每个组将在输入字符串中匹配时包含许多捕获。 在您的示例中,分隔符组将比名称组少一个捕获。
然后,您可以迭代捕获,并使用结果从输入字符串中提取字段并存储值,如下所示:
if( m.Success )
{
Group name = m.Groups["name"];
Group separator = m.Groups["separator"];
int index = 0;
Dictionary<string, string> fields = new Dictionary<string, string>();
for( int x = 0; x < name.Captures.Count; ++x )
{
int separatorIndex = input.Length;
if( x < separator.Captures.Count )
separatorIndex = input.IndexOf(separator.Captures[x].Value, index);
fields.Add(name.Captures[x].Value, input.Substring(index, separatorIndex - index));
index = separatorIndex + 1;
}
// Do something with results.
}
显然,在一个真实的程序中,你必须考虑无效的输入等,这是我在这里没有做的。
我会根据模板创建一个正则表达式,然后使用以下方法解析文本文件:
class Parser
{
private static readonly Regex TemplateRegex =
new Regex(@"\[%(?<field>[^]]+)%\](?<delim>[^[]+)?");
readonly List<string> m_fields = new List<string>();
private readonly Regex m_textRegex;
public Parser(string template)
{
var textRegexString = '^' + TemplateRegex.Replace(template, Evaluator) + '$';
m_textRegex = new Regex(textRegexString);
}
string Evaluator(Match match)
{
// add field name to collection and create regex for the field
var fieldName = match.Groups["field"].Value;
m_fields.Add(fieldName);
string result = "(.*?)";
// add delimiter to the regex, if it exists
// TODO: check, that only last field doesn't have delimiter
var delimGroup = match.Groups["delim"];
if (delimGroup.Success)
{
string delim = delimGroup.Value;
result += Regex.Escape(delim);
}
return result;
}
public IDictionary<string, string> Parse(string text)
{
var match = m_textRegex.Match(text);
var groups = match.Groups;
var result = new Dictionary<string, string>(m_fields.Count);
for (int i = 0; i < m_fields.Count; i++)
result.Add(m_fields[i], groups[i + 1].Value);
return result;
}
}
我会用几行代码来做这件事。 循环遍历模板行,将“[”作为变量名称和其他所有内容作为终止符之间的所有文本。 读取终端的所有文本,将其分配给变量名称,重复。
1- 在此处使用sscanf(line, format, __arglist)
API sscanf(line, format, __arglist)
2-使用字符串拆分喜欢:
public IEnumerable<int> GetDataFromLines(string[] lines)
{
//handle the output data
List<int> data = new List<int>();
foreach (string line in lines)
{
string[] seperators = new string[] { "|", "\"" };
string[] results = line.Split(seperators, StringSplitOptions.RemoveEmptyEntries);
foreach (string result in results)
{
data.Add(int.Parse(result));
}
}
return data;
}
用线测试:
line = "1234|1234567|123\"12345\"12\"123456";
string[] lines = new string[] { line };
GetDataFromLines(lines);
//output list items are:
1234
1234567
123
12345
12
123456
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.