1

我目前正在尝试将 VB6 程序转换为 C#。字符串拆分成结构被广泛使用。例如,

Dim Sample AS String
Sample = "John Doe        New York  Test Comment"

Public Type Struct1
    Name As String * 15
    Address As String * 10
    Comment As String * 20
End Type

Dim dataStruct As Struct1

Set dataStruct = Sample

当 dataStruct 被设置时,它会自动将 value 拆分为 3 个结构成员。在 C# 中是否有特殊功能可以执行此操作。我知道如何做到这一点的唯一方法是通过描述字符串长度和起始位置的属性/注释。还有什么建议吗?

4

5 回答 5

3

您可以查看FileHelpers库,其中包含执行此操作的方法

于 2010-06-10T11:06:29.827 回答
3

您可以尝试使用隐式运算符:

class Program
{
    static void Main(string[] args)
    {
        string sample = "John Doe        New York  Test Comment";
        MyClass c = sample;
    }
}

public class MyClass
{
    public string Name;
    public string Address;
    public string Comment;

    public MyClass(string value)
    {
        //parsing of value and assigning to Name, Adress, Comment comes here
    }

    public static implicit operator MyClass(string value)
    {
        return new MyClass(value);
    }
}

对于字符串值的解析,您可以使用正则表达式。

于 2010-06-10T11:22:40.913 回答
2

我不知道有任何内置方法可以做到这一点,但使用属性对我来说听起来像是一种好方法。然后,您可以编写代码以通过反射设置相关属性。除非字符串中有空格,否则我会将其表示为相对排序和长度而不是起始位置 - 然后你可以找到所有属性,按它们的顺序排序(不应该要求是连续的 - 排序0, 10, 20, 30, 40 可以更容易地在必要时添加额外的属性)并以这种方式计算拆分。

于 2010-06-10T11:04:54.960 回答
1

您可以使用运算符重载来模拟分配行为。这样,目标类还定义了部分的大小,因此每个类都必须知道输入的外观。它比 VB 示例的代码多一点。

示例(语法可能不正确,我很少使用运算符重载):

class DataItem
{
  public String Name {get;set;}
  public String Address {get;set;}
  public String Comment {get;set;}

  public static implicit operator DataItem(string value)
  {
    DataItem item = new DataItem();
    item.Name = string.Substring(0, 10).Trim();
    item.Address = string.Substring(10, 25).Trim();
    item.Comment = string.Substring(25, 45).Trim();
    return item;
  }
}

[...]
DataItem item = sampleString;
[...]

一个更易读的替代方案是隐式创建者模式:

class DataItem
{
  public String Name {get;set;}
  public String Address {get;set;}
  public String Comment {get;set;}

  public static DataItem FromString(String string)
  {
    DataItem item = new DataItem();
    item.Name = string.Substring(0, 10).Trim();
    item.Address = string.Substring(10, 25).Trim();
    item.Comment = string.Substring(25, 45).Trim();
    return item;
  }
}

[...]
DataItem item = DataItem.FromString(sampleString);
[...]
于 2010-06-10T11:14:59.803 回答
1

如果没有 P/Invoke 编组器,这样的结构映射技巧就无法工作。结构的内部组织是不可发现的。JIT 编译器很容易利用这一点,如果这会为结构产生更小的内存大小,它会交换成员。只有 [StructLayout] 才能确定它。

Microsoft.VisualBasic 命名空间中的另一个优点使这很容易做到。TextFieldParser 类可以通过一次调用轻松地转换这样的字符串。例如:

using System;
using System.IO;
using Microsoft.VisualBasic.FileIO;  // NOTE: add reference to Microsoft.VisualBasic

class Program {
    static void Main(string[] args) {
        var strm = new StringReader("John Doe        New York  Test Comment");
        var parse = new TextFieldParser(strm);
        parse.TextFieldType = FieldType.FixedWidth;
        parse.SetFieldWidths(16, 10, 12);
        foreach (var field in parse.ReadFields())
            Console.WriteLine(field.Trim());
        Console.ReadLine();
    }
}

请注意,您发布的原始字符串与结构声明不匹配,我不得不修改字段宽度。另请注意,TextFieldParser 接受任何流,它不必是存储在 StringReader 中的字符串。读取文件的 StreamReader 将是更典型的用途。

于 2010-06-10T12:45:56.710 回答