Wpf 从这种格式的文本文件中提取信息最有效的方法是什么

Wpf 从这种格式的文本文件中提取信息最有效的方法是什么,wpf,vb.net,linq,streamreader,Wpf,Vb.net,Linq,Streamreader,考虑一个存储在联机位置的文本文件,如下所示: ;aiu; [MyEditor45] Name = MyEditor 4.5 URL = http://www.myeditor.com/download/myeditor.msi Size = 3023788 Description = This is the latest version of MyEditor Feature = Support for other file types Feature1 = Support for

考虑一个存储在联机位置的文本文件,如下所示:

    ;aiu;

[MyEditor45]
Name = MyEditor 4.5
URL = http://www.myeditor.com/download/myeditor.msi
Size = 3023788
Description = This is the latest version of MyEditor
Feature = Support for other file types 
Feature1 = Support for different encodings
BugFix = Fix bug with file open
BugFix1 = Fix crash when opening large files
BugFix2 = Fix bug with search in file feature
FilePath = %ProgramFiles%\MyEditor\MyEditor.exe
Version = 4.5
其中详细说明了用户可以下载的应用程序的可能更新信息。我想将其加载到流读取器中,对其进行解析,然后建立一个功能、错误修复等列表,并在wpf列表框中显示给最终用户

我有下面的一段代码,基本上可以获取我的文本文件(首先从本地ini文件中提取其位置,并将其加载到streamReader中。这至少有效,尽管我知道目前没有错误检查,但我只想先建立最有效的方法来解析此文件。其中一个文件不太可能超过250-400行文本

Dim UpdateUrl As String = GetUrl()
    Dim client As New WebClient()
    Using myStreamReader As New StreamReader(client.OpenRead($"{UpdateUrl}"))

        While Not myStreamReader.EndOfStream
            Dim line As String = myStreamReader.ReadLine
            If line.Contains("=") Then
                Dim p As String() = line.Split(New Char() {"="c})
                If p(0).Contains("BugFix") Then
                    MessageBox.Show($" {p(1)}")
                End If
            End If
        End While
    End Using
具体而言,我希望整理有关功能、错误修复和增强功能的信息。虽然我可以构建一个实际上相当混乱的if声明,但我确信必须有一种更有效的方法来实现这一点,可能涉及linq。我欢迎任何建议


我添加了wpf标签,因为有人在阅读本文时比我更有在wpf列表框中显示信息的经验,可能会发现一种有效地定义我要查找的信息的方法,这样它就可以很容易地在wpf列表框中分三个部分显示(功能、增强和错误修复).

Dom,这里是C#中的一个答案。我将尝试立即将其转换为VB.Net。首先,由于文件很小,请将所有文件读入字符串列表。然后选择包含“=”的字符串并将它们解析为可以使用的数据项。此代码将返回一组数据项,然后您可以根据需要显示这些数据项。如果您有LinqPad,您可以测试下面的代码,或者我在这里有代码:

以下是VB.Net版本:

或者,在C#中:

void Main()
{
List fileContent=GetFileContent();
var dataItems=fileContent.Where(c=>c.Contains(“=”)
.选择(c=>GetDataItem(c));
dataItems.Dump();
}    
公共列表GetFileContent()
{
列表内容列表=新列表();
contentList.Add(“sb.app;aiu;”);
内容列表。添加(“”);
contentList.Add(“[MyEditor45]”);
contentList.Add(“Name=MyEditor 4.5”);
contentList.Add(“URL=http://www.myeditor.com/download/myeditor.msi");
contentList.Add(“Size=3023788”);
Add(“Description=这是MyEditor的最新版本”);
contentList.Add(“Feature=支持其他文件类型”);
Add(“Feature1=支持不同的编码”);
Add(“BugFix=修复打开文件的bug”);
Add(“BugFix1=修复打开大文件时的崩溃”);
Add(“BugFix2=使用文件搜索功能修复bug”);
contentList.Add(“文件路径=%ProgramFiles%\\MyEditor\\MyEditor.exe”);
contentList.Add(“版本=4.5”);
返回内容列表;
}
公共数据项GetDataItem(字符串值)
{
var parts=value.Split('=');
var dataItem=新的dataItem()
{
数据类型=零件[0],
数据=零件[1]
};
返回数据项;
}
公共类数据项
{
公共字符串数据类型;
公共字符串数据;
}

Dom,这里是C#中的一个答案。我将尝试立即将其转换为VB.Net。首先,由于文件较小,请将所有文件读入字符串列表。然后选择包含“=”的字符串并将它们解析为可以使用的数据项。此代码将返回一组数据项,然后您可以根据需要显示这些数据项。如果您有LinqPad,您可以测试下面的代码,或者我在这里有代码:

以下是VB.Net版本:

或者,在C#中:

void Main()
{
List fileContent=GetFileContent();
var dataItems=fileContent.Where(c=>c.Contains(“=”)
.选择(c=>GetDataItem(c));
dataItems.Dump();
}    
公共列表GetFileContent()
{
列表内容列表=新列表();
contentList.Add(“sb.app;aiu;”);
内容列表。添加(“”);
contentList.Add(“[MyEditor45]”);
contentList.Add(“Name=MyEditor 4.5”);
contentList.Add(“URL=http://www.myeditor.com/download/myeditor.msi");
contentList.Add(“Size=3023788”);
Add(“Description=这是MyEditor的最新版本”);
contentList.Add(“Feature=支持其他文件类型”);
Add(“Feature1=支持不同的编码”);
Add(“BugFix=修复打开文件的bug”);
Add(“BugFix1=修复打开大文件时的崩溃”);
Add(“BugFix2=使用文件搜索功能修复bug”);
contentList.Add(“文件路径=%ProgramFiles%\\MyEditor\\MyEditor.exe”);
contentList.Add(“版本=4.5”);
返回内容列表;
}
公共数据项GetDataItem(字符串值)
{
var parts=value.Split('=');
var dataItem=新的dataItem()
{
数据类型=零件[0],
数据=零件[1]
};
返回数据项;
}
公共类数据项
{
公共字符串数据类型;
公共字符串数据;
}

给出的答案只集中在第一部分,即将数据转换为可用于显示的结构。但我认为您的主要问题是如何进行实际的整形

我使用了一种稍有不同的方法来收集文件数据,使用Microsoft.VisualBasic.FileIO.TextFieldParser,因为我认为这会使编码变得更简单:

Iterator Function GetTwoItemLines(fileName As String, delimiter As String) _
        As IEnumerable(Of Tuple(Of String, String))
    Using tfp = New TextFieldParser(fileName)
        tfp.TextFieldType = FieldType.Delimited
        tfp.Delimiters = {delimiter}
        tfp.HasFieldsEnclosedInQuotes = False
        tfp.TrimWhiteSpace = False

        While Not tfp.EndOfData
            Dim arr = tfp.ReadFields()
            If arr.Length >= 2 Then
                Yield Tuple.Create(arr(0).Trim(), String.Join(delimiter, arr.Skip(1)).Trim())
            End If
        End While
    End Using
End Function
实际上,与代码中发生的情况相同,但考虑到Andrew对数据丢失的强烈警告:行由
=
字符分割,但行的第二个字段由第一部分之后的所有部分组成,并重新插入分隔符:
String.Join(delimiter,arr.Skip(1)).Trim()

您可以按如下方式使用此功能:

Dim fileContent = GetTwoItemLines(file, "=")
对于显示,我认为最好的方法(就代码行而言最有效)是按行的第一项对行进行分组
Iterator Function GetTwoItemLines(fileName As String, delimiter As String) _
        As IEnumerable(Of Tuple(Of String, String))
    Using tfp = New TextFieldParser(fileName)
        tfp.TextFieldType = FieldType.Delimited
        tfp.Delimiters = {delimiter}
        tfp.HasFieldsEnclosedInQuotes = False
        tfp.TrimWhiteSpace = False

        While Not tfp.EndOfData
            Dim arr = tfp.ReadFields()
            If arr.Length >= 2 Then
                Yield Tuple.Create(arr(0).Trim(), String.Join(delimiter, arr.Skip(1)).Trim())
            End If
        End While
    End Using
End Function
Dim fileContent = GetTwoItemLines(file, "=")
Dim grouping = fileContent.GroupBy(Function(c) c.Item1.TrimEnd("0123456789".ToCharArray())) _
    .Where(Function(k) k.Key = "Feature" OrElse k.Key = "BugFix" OrElse k.Key = "Enhancement")
Imports System.Text.RegularExpressions

Private Function InfoReader(ByVal sourceText As String) As List(Of Dictionary(Of String, String()))
    '1) make array of fragments for each product info
    Dim products = Regex.Split(sourceText, "(?=\[\s*\w+\s*])")
    '2) declare variables needed ahead
    Dim productProperties As Dictionary(Of String, String)
    Dim propertyNames As String()
    Dim productGroupedProperties As Dictionary(Of String, String())
    Dim result As New List(Of Dictionary(Of String, String()))
    '2) iterate along fragments
    For Each product In products
        '3) work only in significant fragments ([Product]...)
        If Regex.IsMatch(product, "\A\[\s*\w+\s*]") Then
            '4) make array of property lines and extract dictionary of property/description
            productProperties = Regex.Split(product, "(?=^\w+\s*=)", RegexOptions.Multiline).Where(
            Function(s) s.Contains("="c)
            ).ToDictionary(
            Function(s) Regex.Match(s, "^\w+(?=\s*=)").Value,
            Function(s) Regex.Match(s, "(?<==\s+).*(?=\s+)").Value)
            '5) extract distinct property names, ignoring numbered repetitions
            propertyNames = productProperties.Keys.Select(Function(s) s.TrimEnd("0123456789".ToCharArray)).Distinct.ToArray
            '6) make dictionary of distinctProperty/Array(Of String){description, description1, ...}
            productGroupedProperties = propertyNames.ToDictionary(
            Function(s) s,
            Function(s) productProperties.Where(
                Function(kvp) kvp.Key.StartsWith(s)
                ).Select(
                Function(kvp) kvp.Value).ToArray)
            '7) enlist dictionary to result
            result.Add(productGroupedProperties)
        End If
    Next
    Return result
End Function