繁体   English   中英

使用C#解析具有自定义格式的文本文件

[英]Parsing a text file with a custom format in C#

我有一堆具有自定义格式的文本文件,如下所示:

App Name    
Export Layout

Produced at 24/07/2011 09:53:21


Field Name                             Length                                                       

NAME                                   100                                                           
FULLNAME1                              150                                                           
ADDR1                                  80                                                           
ADDR2                                  80          

任何空格都可以是制表符或空格。 该文件可以包含任意数量的字段名称和长度。

我想获取所有字段名称及其对应的字段长度,也许将它们存储在字典中。 该信息将用于处理具有上述字段名称和字段长度的相应的固定宽度数据文件。

我知道如何使用ReadLine()跳过行。 我不知道该怎么说:“当您到达以“字段名称”开头的行时,再跳过一行,然后从下一行开始,抓住左栏中的所有单词以及右列。”

我已经尝试过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版本,因为它更具可读性和可维护性(imo)。

基于标题行位置固定的假设,我们可以考虑实际的键值对从第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()进行空格分隔。 这将为您获取您的字段名和长度字符串。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM