有没有办法解析Visual Basic中的位置文件?

时间:2014-12-04 04:06:53

标签: vb.net parsing

我有一个输入文件,其中包含位置格式的记录(例如,列First Name位于1到10位)

像这样:
John Doe john@example.com

这显然过于简单了。我真的有超过25列,所以使用Mid是可能的,但过于复杂。我想我可以编写一个可以解析它的类,但我想确保在浪费时间之前这些不是更好的方法。

2 个答案:

答案 0 :(得分:3)

Microsoft.VisualBasic.FileIO.TextFieldParser类可以解析固定宽度格式。基本用法是创建类的实例,设置属性以指示格式是固定宽度,调用方法以指定每列的宽度,然后启动循环以一次读取一条记录的数据。这是an example from MSDN。在此示例中,文件有4列,宽度为5,宽度为10,宽度为11,最后一列为无限长度(-1)。

Using Reader As New Microsoft.VisualBasic.FileIO.TextFieldParser("C:\TestFolder\test.log")
  Reader.TextFieldType = Microsoft.VisualBasic.FileIO.FieldType.FixedWidth
  Reader.SetFieldWidths(5, 10, 11, -1)

  Dim currentRow As String()
  While Not Reader.EndOfData
    Try
      currentRow = Reader.ReadFields()
      Dim currentField As String 
      For Each currentField In currentRow
        MsgBox(currentField)
      Next 
    Catch ex As Microsoft.VisualBasic.FileIO.MalformedLineException
      MsgBox("Line " & ex.Message & "is not valid and will be skipped.")
    End Try
  End While 
End Using

答案 1 :(得分:1)

Ryan的答案更合适(不知道上课存在)你需要什么。

然而,由于我已经写了这个C#版本,我将在此发布,因为它可能会在将来为其他人派上用场


基本上,创建一些委托来处理每列的实际操作。然后循环遍历每个部分的行和Substring。正如评论中指出的那样,Substring并不是非常优化,但是,很容易理解这一点并改变实际读取列的方式。

VB.NET版本

Public Class Person

    Public Property FirstName As String
    Public Property LastName As String
    Public Property Email As String

End Class

Public Class ColumnHandler

    Public Property Process As Action(Of Person, String)

    Public Property Length As Integer

    Public Sub New(processAction As Action(Of Person, String), columnLength As Integer)
        Process = processAction
        Length = columnLength
    End Sub

End Class

Module Module1

    Sub Main()

        Dim columnHandlers() As ColumnHandler =
            {
                New ColumnHandler(Sub(p, s) p.FirstName = s, 10),
                New ColumnHandler(Sub(p, s) p.LastName = s, 10),
                New ColumnHandler(Sub(p, s) p.Email = s, 16)
            }

        Dim fileLines() As String =
            {
                "John      Doe       john@example.com",
                "Ty        Cobb      anon@example.com"
            }

        Dim people As New List(Of Person)

        For Each line As String In fileLines

            Dim currentPosition As Integer = 0
            Dim person As New Person()

            For Each columnHandler As ColumnHandler In columnHandlers
                columnHandler.Process.Invoke(person, line.Substring(currentPosition, columnHandler.Length).Trim())
                currentPosition += columnHandler.Length
            Next

            people.Add(person)

        Next

        Console.WriteLine(people.Count.ToString())
        Console.WriteLine(people(1).LastName)
        Console.ReadLine()

    End Sub

End Module

C#版(因为我显然不知道如何阅读问号或标题)

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Email { get; set; }
}

void Main()
{
    var columnHandlers = new[]
    {
        new {Process = new Action<Person, string>((p, s) => p.FirstName = s), Length = 10},
        new {Process = new Action<Person, string>((p, s) => p.LastName = s), Length = 10},
        new {Process = new Action<Person, string>((p, s) => p.Email = s), Length = 16},
    };

    //Replace this with a stream or however you were going to get/read the lines
    var fileLines = new[]
    {
        "John      Doe       john@example.com",
        "Ty        Cobb      anon@example.com",
    };

    var people = new List<Person>();

    foreach (var line in fileLines)
    {
        var currentPosition = 0;
        var person = new Person();
        foreach (var columnHandler in columnHandlers)
        {
            columnHandler.Process(person, line.Substring(currentPosition, columnHandler.Length).Trim());
            currentPosition += columnHandler.Length;
        }

        people.Add(person);
    }

    Console.WriteLine(people.Count.ToString());
    Console.WriteLine(people[1].LastName);
}