我有一个文本文件,分为多个部分,每个部分大约10行左右。我正在使用File.ReadAllLines将文件读入一个数组,每个数组元素一行,然后我尝试解析文件的每个部分以恢复一些的数据。我将结果存储在列表中,并希望最终将列表导出到csv。
我的for循环给了我麻烦,因为它循环了适当的次数,但每次只从文本文件的第一部分拉取数据而不是从第一部分拉出数据然后继续从下一节中提取数据。我确定我在for循环或每个循环中都做错了。任何帮助我解决这个问题的线索将非常感激!谢谢 大卫
到目前为止我的代码:
namespace ParseAndExport
{
class Program
{
static readonly string sourcefile = @"Path";
static void Main(string[] args)
{
string[] readInLines = File.ReadAllLines(sourcefile);
int counter = 0;
int holderCPStart = counter + 3;//Changed Paths will be an different number of lines each time, but will always start 3 lines after the startDiv
/*Need to find the start of the section and the end of the section and parse the bit in between.
* Also need to identify the blank line that occurs in each section as it is essentially a divider too.*/
int startDiv = Array.FindIndex(readInLines, counter, hyphens72);
int blankLine = Array.FindIndex(readInLines, startDiv, emptyElement);
int endDiv = Array.FindIndex(readInLines, counter + 1, hyphens72);
List<string> results = new List<string>();
//Test to see if FindIndexes work. Results should be 0, 7, 9 for 1st section of sourcefile
/*Console.WriteLine(startDiv);
Console.WriteLine(blankLine);
Console.WriteLine(endDiv);*/
//Check how long the file is so that for testing we know how long the while loop should run for
//Console.WriteLine(readInLines.Length);
//sourcefile has 5255 lines (elements) in the array
for (int i = 0; i <= readInLines.Length; i++)
{
if (i == startDiv)
{
results = (readInLines[i + 1].Split('|').Select(p => p.Trim()).ToList());
string holderCP = string.Join(Environment.NewLine, readInLines, holderCPStart, (blankLine - holderCPStart - 1)).Trim();
results.Add(holderCP);
string comment = string.Join(" ", readInLines, blankLine + 1, (endDiv - (blankLine + 1)));//in case the comment is more than one line long
results.Add(comment);
i = i + 1;
}
else
{
i = i + 1;
}
foreach (string result in results)
{
Console.WriteLine(result);
}
//csvcontent.AppendLine("Revision Number, Author, Date, Time, Count of Lines, Changed Paths, Comments");
/* foreach (string result in results)
{
for (int x = 0; x <= results.Count(); x++)
{
StringBuilder csvcontent = new StringBuilder();
csvcontent.AppendLine(results[x] + "," + results[x + 1] + "," + results[x + 2] + "," + results[x + 3] + "," + results[x + 4] + "," + results[x + 5]);
x = x + 6;
string csvpath = @"addressforcsvfile";
File.AppendAllText(csvpath, csvcontent.ToString());
}
}*/
}
Console.ReadKey();
}
private static bool hyphens72(String h)
{
if (h == "------------------------------------------------------------------------")
{
return true;
}
else
{
return false;
}
}
private static bool emptyElement(String ee)
{
if (ee == "")
{
return true;
}
else
{
return false;
}
}
}
}
答案 0 :(得分:0)
逻辑似乎错了。代码本身也存在问题。我不确定你究竟想要做什么。无论如何,我希望能提供一些帮助:
if(i == startDiv)检查我是否等于startDiv。我假设当满足这个条件时发生的逻辑就是你所说的“从第一部分中提取数据”。这是正确的,因为当我等于startDiv时你只运行这段代码。
你在for循环中增加了计数器I,这本身也增加了计数器i。
如果2.中的问题不存在那么我建议不要在if(i == startDiv)的true和false条件下执行相同的操作“i = i + 1”
鉴于我认为这个文件实际上可能很庞大,不建议将它存储在内存中,但只是逐行读取文件并逐行处理。目前没有明显的原因你想要消耗这么多的内存,除非是因为这个API“File.ReadAllLines(sourcefile)”的便利性。我不会太害怕读这样的文件:
Try (BufferedReader br = new BufferedReader(new FileReader (file))) {
String line;
while ((line = br.readLine()) != null) {
// process the line.
}
}
您可以跳过这些行,直到您通过该行等于连字符72的位置。
然后对于每一行,使用您在(i == startDiv)的真实情况下提供的代码处理该行,或者至少从您描述的内容处理该行,这是我假设您正在尝试执行的操作。
答案 1 :(得分:0)
看起来你试图抓住文件中不是“------”的所有行并将它们放入字符串列表中。
你可以试试这个:
var lineswithoutdashes = readInLines.Where(x => x != hyphens72).Select(x => x).ToList();
现在您可以使用此列表并使用“|”进行拆分提取你想要的字段
答案 2 :(得分:0)
有几件事可以改进。
我会使用ReadLines
而不是File.ReadAllLines(
,因为ReadAllLines会读取所有的行。 ReadLines将流式传输。
使用行results = (readInLines[i + 1].Split('|').Select(p => p.Trim()).ToList());
,您将覆盖之前的结果列表。您最好使用results.AddRange()
添加新结果。
for (int i = 0; i <= readInLines.Length; i++)
表示当长度= 10时,它将进行11次迭代。 (1太多)(删除=
)
Array.FindIndex(readInLines, counter, hyphens72);
会进行扫描。在大文件上,完全阅读它们并在其中搜索需要很长时间。 尝试仅触摸一行。
我无法测试你在做什么,但这里有一个提示:
IEnumerable<string> readInLines = File.ReadLines(sourcefile);
bool started = false;
List<string> results = new List<string>();
foreach(var line in readInLines)
{
// skip empty lines
if(emptyElement(line))
continue;
// when dashes are found, flip a boolean to activate the reading mode.
if(hyphens72(line))
{
// flip state.. (start/end)
started != started;
}
if(started)
{
// I don't know what you are doing here precisely, do what you gotta do. ;-)
results.AddRange((line.Split('|').Select(p => p.Trim()).ToList()));
string holderCP = string.Join(Environment.NewLine, readInLines, holderCPStart, (blankLine - holderCPStart - 1)).Trim();
results.Add(holderCP);
string comment = string.Join(" ", readInLines, blankLine + 1, (endDiv - (blankLine + 1)));//in case the comment is more than one line long
results.Add(comment);
}
}
foreach (string result in results)
{
Console.WriteLine(result);
}
答案 3 :(得分:0)
int startDiv
将返回包含hyphens72
的行号。
因此,您当前的for
循环只会复制到与计算出的行号匹配的单行结果。
我想你想在当前行中搜索startDiv
的位置?
const string hyphens72;
// loop over lines
for (var lineNumber = 0; lineNumber <= readInLines.Length; lineNumber++) {
string currentLine = readInLines[lineNumber];
int startDiv = currentLine.IndexOf(hyphens72);
// loop over characters in line
for (var charIndex = 0; charIndex < currentLine.Length; charIndex++) {
if (charIndex == startDiv) {
var currentCharacter = currentLine[charIndex];
// write to result ...
}
else {
continue; // skip this character
}
}
}
答案 4 :(得分:0)
你可能想要从这样的课开始。我不知道每个部分是以一行连字符开头,还是介于两者之间。这应该处理任何一种情况。
这将是你的巨大字符串列表(文件中的行)并将其分成块 - 每个块是一组行(根据你的OP,大约10行)。
原因是尝试读取文件,查找连字符以及同时处理文件内容会不必要地复杂化。相反,一个类接受输入并将其分成块。就是这样。
另一个类可能会读取该文件并将其内容传递给此类以将其分解。然后输出是单个文本块。
然后另一个类可以处理10个左右的那些单独的部分,而不必担心连字符或者chunk与另一个分隔的内容。
既然这些类中的每一个都在做自己的事情,那么分别为每个类编写单元测试会更容易。您可以测试您的“处理”类是否接收到大约10行的数组,并执行它应该对它们执行的任何操作。
public class TextSectionsParser
{
private readonly string _delimiter;
public TextSectionsParser(string delimiter)
{
_delimiter = delimiter;
}
public IEnumerable<IEnumerable<string>> ParseSections(IEnumerable<string> lines)
{
var result = new List<List<string>>();
var currentList = new List<string>();
foreach (var line in lines)
{
if (line == _delimiter)
{
if(currentList.Any())
result.Add(currentList);
currentList = new List<string>();
}
else
{
currentList.Add(line);
}
}
if (currentList.Any() && !result.Contains(currentList))
{
result.Add(currentList);
}
return result;
}
}