解析c#中自定义格式的文本文件
本文关键字:文本 文件 格式 自定义 解析 | 更新日期: 2023-09-27 18:14:27
我有一堆自定义格式的文本文件,看起来像这样:
App Name
Export Layout
Produced at 24/07/2011 09:53:21
Field Name Length
NAME 100
FULLNAME1 150
ADDR1 80
ADDR2 80
空格可以是制表符或空格。该文件可以包含任意数量的字段名和长度。
我想获得所有的字段名和它们对应的字段长度,并可能将它们存储在字典中。此信息将用于处理具有上述字段名称和字段长度的相应固定宽度数据文件。
我知道如何使用ReadLine()跳过行。我不知道的是怎么说:"当你看到以‘Field Name’开头的那一行时,再跳过一行,然后从下一行开始,抓住左边列的所有单词和右边列的数字。"
我已经尝试过String.Trim(),但这并没有删除中之间的空白。
提前感谢。
您可以使用SkipWhile(l => !l.TrimStart().StartsWith("Field Name")).Skip(1)
:
Dictionary<string, string> allFieldLengths = File.ReadLines("path")
.SkipWhile(l => !l.TrimStart().StartsWith("Field Name")) // skips lines that don't start with "Field Name"
.Skip(1) // go to next line
.SkipWhile(l => string.IsNullOrWhiteSpace(l)) // skip following empty line(s)
.Select(l =>
{ // anonymous method to use "real code"
var line = l.Trim(); // remove spaces or tabs from start and end of line
string[] token = line.Split(new[] { ' ', ''t' }, StringSplitOptions.RemoveEmptyEntries);
return new { line, token }; // return anonymous type from
})
.Where(x => x.token.Length == 2) // ignore all lines with more than two fields (invalid data)
.Select(x => new { FieldName = x.token[0], Length = x.token[1] })
.GroupBy(x => x.FieldName) // groups lines by FieldName, every group contains it's Key + all anonymous types which belong to this group
.ToDictionary(xg => xg.Key, xg => string.Join(",", xg.Select(x => x.Length)));
line.Split(new[] { ' ', ''t' }, StringSplitOptions.RemoveEmptyEntries)
将按空格和制表符分割,并忽略所有空格。使用GroupBy
确保所有键在字典中是唯一的。在重复字段名的情况下,Length
将用逗号连接。
编辑:由于您请求的是非linq版本,这里是它:
Dictionary<string, string> allFieldLengths = new Dictionary<string, string>();
bool headerFound = false;
bool dataFound = false;
foreach (string l in File.ReadLines("path"))
{
string line = l.Trim();
if (!headerFound && line.StartsWith("Field Name"))
{
headerFound = true;
// skip this line:
continue;
}
if (!headerFound)
continue;
if (!dataFound && line.Length > 0)
dataFound = true;
if (!dataFound)
continue;
string[] token = line.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
if (token.Length != 2)
continue;
string fieldName = token[0];
string length = token[1];
string lengthInDict;
if (allFieldLengths.TryGetValue(fieldName, out lengthInDict))
// append this length
allFieldLengths[fieldName] = lengthInDict + "," + length;
else
allFieldLengths.Add(fieldName, length);
}
我更喜欢LINQ版本,因为它更具可读性和可维护性。
基于标题行位置固定的假设,我们可以考虑从第9行开始实际的键值对。然后,使用ReadAllLines
方法从文件返回一个String
数组,我们从索引8开始处理:
string[] lines = File.ReadAllLines(filepath);
Dictionary<string,int> pairs = new Dictionary<string,int>();
for(int i=8;i<lines.Length;i++)
{
string[] pair = Regex.Replace(lines[i],"(''s)+",";").Split(';');
pairs.Add(pair[0],int.Parse(pair[1]));
}
这是一个框架,没有考虑异常处理,但我想它应该让你开始。
可以使用String.StartsWith()
检测"FieldName"。然后是带null参数的String.Split()
,用空格分隔。这将得到您的字段名和长度字符串。