读取文本文件中特定字符串后的行,然后将数据存储在列表中

时间:2016-03-01 21:01:35

标签: c# regex streamreader

我有一个程序来读取文本文件,我希望它在文本文件中的某个标题之后收集数据,在本例中为[HRData]。一旦流式读取器到达[HRData],我希望它在此之后读取每一行并将每行存储在列表中,但允许我访问单独的数字。

文本文件是这样的:

[HRZones]
190
175
162
152
143
133
0
0
0
0
0

[SwapTimes]

[Trip]
250
0
3978
309
313
229
504
651
//n header 
[HRData]
91  154 70  309 83  6451
91  154 70  309 83  6451
92  160 75  309 87  5687
94  173 80  309 87  5687
96  187 87  309 95  4662
100 190 93  309 123 4407
101 192 97  309 141 4915
103 191 98  309 145 5429

所以参考文本文件,我希望它存储[HRData]之后的第一行,并允许我访问每个变量,例如91[0]

如果单词与正则表达式匹配,我的代码已存储到列表中,但我不知道如何编写代码以在[HRData]之类的特定字符串后读取。

if (squareBrackets.Match(line).Success) {
 titles.Add(line);
 if (textAfterTitles.Match(line).Success) {
  textaftertitles.Add(line);

 }
}

这是我到目前为止的尝试:

if (line.Contains("[HRData]")) {
 inttimes = true;
 MessageBox.Show("HRDATA Found");
 if (inttimes == true) {
  while (null != (line = streamReader.ReadLine())) {
   //ADD LINE AND BREAK UP INTO PARTS S
  }
 }
}

3 个答案:

答案 0 :(得分:3)

您可以调用LINQ友好方法File.ReadLines,然后您可以使用LINQ获取所需的部分:

List<string> numbers = File.ReadLines("data.txt")
                           .SkipWhile(line => line != "[HRData]") 
                           .Skip(1)
                           .SelectMany(line => line.Split())
                           .ToList();

Console.WriteLine(numbers[0]); // 91

修改 - 这会在一个List<string>中为您提供所有数字,如果您想保留订单行,请使用Select代替SelectMany

List<List<string>> listsOfNums = File.ReadLines("data.txt")
                                     .SkipWhile(line => line != "[HRData]") 
                                     .Skip(1)
                                     .Select(line => line.Split().ToList())
                                     .ToList();

请注意,这需要额外的索引来获取单个数字:

Console.WriteLine(listsOfNums[0][0]); // 91

答案 1 :(得分:3)

您可以使用变量来跟踪当前部分:

var list = new List<int[]>();
using (StreamReader streamReader = ...)
{
    string line;
    string sectionName = null;
    while (null != (line = streamReader.ReadLine()))
    {
        var sectionMatch = Regex.Match(line, @"\s*\[\s*(?<NAME>[^\]]+)\s*\]\s*");
        if (sectionMatch.Success)
        {
            sectionName = sectionMatch.Groups["NAME"].Value;
        }
        else if (sectionName == "HRData")
        {
            // You can process lines inside the `HRData` section here.

            // Getting the numbers in the line, and adding to the list, one array for each line.
            var nums = Regex.Matches(line, @"\d+")
                .Cast<Match>()
                .Select(m => m.Value)
                .Select(int.Parse)
                .ToArray();

            list.Add(nums);
        }
    }
}

答案 2 :(得分:2)

假设您当前的代码尝试有效,我还没有通过验证...

您可以执行以下操作:

git fetch

或者,如果您想要一个二维列表,以便您可以逐行引用这些数字,则可以使用嵌套列表。对于外循环的每次运行,创建一个新列表并将其添加到元素(元素将为List<int> elements = new List<int>(); while (null != (line = streamReader.ReadLine())) { if(line.Contains("[")) { //Prevent reading in the next section break; } string[] split = line.Split(Convert.ToChar(" ")); //Each element in split will be each number on each line. for(int i=0;i<split.Length;i++) { elements.Add(Convert.ToInt32(split[i])); } } )。

<强> 修改

请注意,请注意Convert.ToInt32()函数。它应该在try catch语句中,以防某些文本被读入而不是数字。

<强> 修改

好的..让日常工作更加健壮(根据我的评论):

首先确保例程不会超出您的数字块。我不确定你列出的块之外是什么,所以这取决于你,但它应采取以下形式:

List<List<int>>

接下来要预先设置分割值的格式。在for语句中:

If(line.Contains("[") || line.Contains("]") || etc etc etc)
{
    break;
}

要访问各个数字(假设您使用的是单维列表),有几种方法可以执行此操作。如果要按索引值访问:

for(int i=0;i<split.Length;i++)
{
    string val = split[i].Trim(); //Get rid of white space
    val = val.Replace("\r\n","");  //Use one of these to trim every character.
    val = val.Replace("\n","");
    try
    {
        elements.Add(Convert.ToInt32());
    }
    catch (Exception ex)
    {
        string err = ex.Message;
        //You might try formatting the split value even more here and retry convert
    }

}

如果你想迭代值列表:

elements.ElementAt(index)

如果您需要确切知道该值的来源,我建议使用2d列表。它将实现如下(我正在从原始代码片段复制我的代码,因此假设添加了所有错误检查!)

foreach(int val in elements)
{
}

现在逐行访问每个元素:

List<List<int>> elements = new List<List<int>>();
while (null != (line = streamReader.ReadLine())) 
{
    if(line.Contains("["))
    {
        //Prevent reading in the next section
        break;
    }
    List<int> newLine = new List<int>();
    string[] split = line.Split(Convert.ToChar(" "));
    //Each element in split will be each number on each line.
    for(int i=0;i<split.Length;i++)
    {
        newLine.Add(Convert.ToInt32(split[i]));
    }
    elements.Add(newLine);
}

或者,如果需要直接引用行索引和列索引

foreach(var line in elements)
{
    //line is a List<int>
    int value = line.ElementAt(index); //grab element at index for the given line.
}

小心所有这些直接索引引用。您可以很容易地获得索引超出范围的问题。

另一件事......你应该在Convert.ToInt语句中放置一个断点,并找到它正在破坏的字符串。如果你可以假设数据输入是一致的,那么确切地找到破坏转换的字符串将帮助你创建一个处理正在过滤的特定字符的例程。我会猜测该方法在尝试时会破坏将最后一个拆分值转换为整数,我们没有删除行结尾。