C#如何解析格式不一致的文本文件,忽略不需要的信息
有点背景。我对在专业环境中使用C#还不熟悉。我的经验主要是SQL。我有一个文件,我需要通过解析来提取某些信息。我知道如何解析每一行,但我一直在搜索特定的信息片段。我对有人帮我完成这段代码不感兴趣。相反,我感兴趣的是关于我可以从这里走到哪里的指针。 下面是我编写的代码示例C#如何解析格式不一致的文本文件,忽略不需要的信息,c#,C#,有点背景。我对在专业环境中使用C#还不熟悉。我的经验主要是SQL。我有一个文件,我需要通过解析来提取某些信息。我知道如何解析每一行,但我一直在搜索特定的信息片段。我对有人帮我完成这段代码不感兴趣。相反,我感兴趣的是关于我可以从这里走到哪里的指针。 下面是我编写的代码示例 class Program { private static Dictionary<string, List<string>> _arrayLists = new Dictionary<st
class Program
{
private static Dictionary<string, List<string>> _arrayLists = new Dictionary<string, List<string>>();
static void Main(string[] args)
{
string filePath = "c:\\test.txt";
StreamReader reader = new StreamReader(filePath);
string line;
while (null !=(line = reader.ReadLine()))
{
if (line.ToLower().Contains("disconnected"))
{
// needs to continue on search for Disconnected or Subscribed
}
else
{
if (line.ToLower().Contains("subscribed"))
{
// program needs to continue reading file
// looking for and assigning values to
// dvd, cls, jhd, dxv, hft
// records start at Subscribed and end at ;
}
}
}
}
}
编辑
我对这个模糊的问题表示歉意。我必须学会如何提出更好的问题
我的思考过程是确保程序将订阅和之间的所有细节关联起来代码>作为一条记录。我想我感到困惑的部分是读台词。在我的脑海中,我看到循环读取订阅的行,然后进入一个方法,读取下一行并赋值,依此类推,直到它到达代码>。一旦这样做了,我就试图弄清楚如何告诉程序退出该方法,但要继续从分号后面的行中读取。也许我想得太多了
我会采纳别人给我的建议,看看我能想出什么办法来解决这个问题。谢谢。与所有问题的代码解决方案一样,有许多可能的方法可以实现您想要的。有些会比其他更好。下面是一个可以帮你指出正确方向的方法
您可以检查字符串是否以关键字或值(如“dvd”)开头(请参阅)
如果是,则可以将字符串拆分为一组部分(请参见)
然后,可以使用所需值的索引从字符串数组中获取每个部分的值
使用检索到的值执行所需的操作
继续检查每一行的关键业务规则(即,将结束该部分的分号)。也许您可以检查字符串的最后一个字符。(见
从你现在的问题来看,不清楚你在努力解决什么具体问题。我建议你编辑你的问题,提供你想克服的具体挑战。目前你的问题陈述是“在搜索特定信息时遇到了困难”。这是不具体的
话虽如此,我将尽力帮助你
首先,如果
是这样的话,你永远不会进入:
line.ToLower().Contains("Disconnected")
在这里,您将所有字符转换为小写,然后尝试在其中找到一个大写字母“D”
的子字符串。上面的表达式(几乎)总是计算为false
其次,为了让你的应用程序做你想做的事情,它需要跟踪当前的解析状态。我现在将忽略“断开连接”位,因为你还没有展示它的意义
我将假设您正在尝试查找文件中已订阅的分号和第一个分号之间的所有内容。我还将对构成字符串的内容做一些其他假设,我不会在这里列出。这些假设可能是错误的,但根据您提供的信息,这是我的最佳猜测
您的程序将在“查找订阅”状态下启动。您已经设置了读取循环,这很好。在该循环中,您读取文件的行,并找到一个包含word subscription的行
一旦您找到这样的行,您的解析器需要移动到“解析订阅”状态。在这种状态下,当您阅读行时,您会查找类似于jjd=768
的行,可能在末尾带有分号。您可以使用正则表达式检查行是否与模式匹配
正则表达式还可以将匹配划分为捕获组,以便您可以分别提取名称(jjd
)和值(768
)。分号的存在或不存在可能是另一个正则表达式组
请注意,正则表达式不是处理此问题的唯一方法,但这是第一个想到的方法
然后将这些行与正则表达式进行匹配,并提取名称和值,直到遇到分号,然后切换回“查找订阅”状态
您可以使用当前状态来决定如何处理下一个读取行
继续,直到文件结束
一般来说,您需要仔细阅读解析
希望这有帮助。在处理包含半结构化数据的文本文件时,状态变量可以简化算法。在下面的代码中,使用布尔状态变量isInRecord
跟踪记录中的行
using System;
using System.Collections.Generic;
using System.IO;
namespace ConsoleApplication19
{
public class Program
{
private readonly static String _testData = @"
test information
annoying information
Subscribed more annoying info
more annoying info
dvd = 234,
cls = 453,
jhd = 567,
more annoying info
more annoying info
dxv = 456,
hft = 876;
more annoying info
test information
annoying information
Subscribed more annoying info
more annoying info
dvd = 234,
cls = 455,
more annoying info
more annoying info
dxv = 456,
hft = 876,
jjd = 768;
more annoying info
test information
annoying information
Disconnected more annoying info
more annoying info
more annoying info";
public static void Main(String[] args)
{
/* Create a temporary file containing the test data. */
var testFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), Path.GetRandomFileName());
File.WriteAllText(testFile, _testData);
try
{
var p = new Program();
var records = p.GetRecords(testFile);
foreach (var kvp in records)
{
Console.WriteLine("Record #" + kvp.Key);
foreach (var entry in kvp.Value)
{
Console.WriteLine(" " + entry);
}
}
}
finally
{
File.Delete(testFile);
}
}
private Dictionary<String, List<String>> GetRecords(String path)
{
var results = new Dictionary<String, List<String>>();
var recordNumber = 0;
var isInRecord = false;
using (var reader = new StreamReader(path))
{
String line;
while ((line = reader.ReadLine()) != null)
{
line = line.Trim();
if (line.StartsWith("Disconnected"))
{
// needs to continue on search for Disconnected or Subscribed
isInRecord = false;
}
else if (line.StartsWith("Subscribed"))
{
// program needs to continue reading file
// looking for and assigning values to
// dvd, cls, jhd, dxv, hft
// records start at Subscribed and end at ;
isInRecord = true;
recordNumber++;
}
else if (isInRecord)
{
// Check if the line has a general format of "something = something".
var parts = line.Split("=".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
if (parts.Length != 2)
continue;
// Update the relevant dictionary key, or add a new key.
List<String> entries;
if (results.TryGetValue(recordNumber.ToString(), out entries))
entries.Add(line);
else
results.Add(recordNumber.ToString(), new List<String>() { line });
// Determine if the isInRecord state variable should be toggled.
var lastCharacter = line[line.Length - 1];
if (lastCharacter == ';')
isInRecord = false;
}
}
}
return results;
}
}
}
使用系统;
使用System.Collections.Generic;
使用System.IO;
命名空间控制台应用程序19
{
公共课程
{
私有只读静态字符串_testData=@”
测试信息
烦人的信息
订阅了更多恼人的信息
更烦人的信息
dvd=234,
cls=453,
jhd=567,
更烦人的信息
更烦人的信息
dxv=456,
hft=876;
更烦人的信息
测试信息
烦人的信息
订阅了更多恼人的信息
更烦人的信息
dvd=234,
cls=455,
更烦人的信息
更烦人的信息
dxv=456,
hft=876,
jjd=768;
更烦人的信息
测试信息
烦人的信息
断开连接更烦人的信息
更烦人的信息
更烦人的信息”;
公共静态void Main(字符串[]args)
{
/*创建包含测试数据的临时文件*/
var testFile=Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),Path.GetRandomFileName();
writealText(testFile,_testData);
尝试
{
var p=新程序();
var records=p.GetRecords(testFile);
foreach(记录中的var kvp)
{
Console.WriteLine(“记录#”+kvp.Key);
弗雷奇
using System;
using System.Collections.Generic;
using System.IO;
namespace ConsoleApplication19
{
public class Program
{
private readonly static String _testData = @"
test information
annoying information
Subscribed more annoying info
more annoying info
dvd = 234,
cls = 453,
jhd = 567,
more annoying info
more annoying info
dxv = 456,
hft = 876;
more annoying info
test information
annoying information
Subscribed more annoying info
more annoying info
dvd = 234,
cls = 455,
more annoying info
more annoying info
dxv = 456,
hft = 876,
jjd = 768;
more annoying info
test information
annoying information
Disconnected more annoying info
more annoying info
more annoying info";
public static void Main(String[] args)
{
/* Create a temporary file containing the test data. */
var testFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), Path.GetRandomFileName());
File.WriteAllText(testFile, _testData);
try
{
var p = new Program();
var records = p.GetRecords(testFile);
foreach (var kvp in records)
{
Console.WriteLine("Record #" + kvp.Key);
foreach (var entry in kvp.Value)
{
Console.WriteLine(" " + entry);
}
}
}
finally
{
File.Delete(testFile);
}
}
private Dictionary<String, List<String>> GetRecords(String path)
{
var results = new Dictionary<String, List<String>>();
var recordNumber = 0;
var isInRecord = false;
using (var reader = new StreamReader(path))
{
String line;
while ((line = reader.ReadLine()) != null)
{
line = line.Trim();
if (line.StartsWith("Disconnected"))
{
// needs to continue on search for Disconnected or Subscribed
isInRecord = false;
}
else if (line.StartsWith("Subscribed"))
{
// program needs to continue reading file
// looking for and assigning values to
// dvd, cls, jhd, dxv, hft
// records start at Subscribed and end at ;
isInRecord = true;
recordNumber++;
}
else if (isInRecord)
{
// Check if the line has a general format of "something = something".
var parts = line.Split("=".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
if (parts.Length != 2)
continue;
// Update the relevant dictionary key, or add a new key.
List<String> entries;
if (results.TryGetValue(recordNumber.ToString(), out entries))
entries.Add(line);
else
results.Add(recordNumber.ToString(), new List<String>() { line });
// Determine if the isInRecord state variable should be toggled.
var lastCharacter = line[line.Length - 1];
if (lastCharacter == ';')
isInRecord = false;
}
}
}
return results;
}
}
}