1

有谁知道如何分割这个文件

1 TESTAAA      SERNUM    A DESCRIPTION
2 TESTBBB      ANOTHR    ANOTHER DESCRIPTION
3 TESTXXX      BLAHBL

每列都有固定的宽度,我打算用正则表达式来做,但我不知道该怎么做。

{id} {firsttext} {serialhere} {description}
 4    22          6            30+

有人推荐这样的模式 (.{4})(.{22})(.{6})(.+)?然后通过 split(' ') 将其拆分,但用户表示这不适用于没有价值的列,但即便如此,他也没有做任何示例。

我也听说过 TextFieldParser,但它在性能方面存在一些问题。

谁能告诉我如何按固定宽度分割?

谢谢。

4

3 回答 3

4

没有任何理由不这样做,我可能只会使用Substring.

话虽如此,正则表达式也应该起作用。

以下示例适用于显示的输入(而不是您提供的数字),并假设序列号是必填字段,但可能不会占用其整个长度 + 描述是可选的。如果这些假设不正确,请按照该原则进行调整。

string input = @"1 TESTAAA      SERNUM    A DESCRIPTION
2 TESTBBB      ANOTHR    ANOTHER DESCRIPTION
3 TESTXXX      BLAHBL";

var split = input.Split('\n').Select(s => new {
        Id = s.Substring(0, 2),
        FirstText = s.Substring(2, 13),
        Serial = s.Substring(15, Math.Min(s.Length-15, 10)),
        Description = s.Length > 25 ? s.Substring(25) : String.Empty
 });

或者作为一个解释性示例,具有更明显的命名和更清晰的序列长度示例:

int idStart = 0;
int idLength = 2;
int firstTextStart = idStart + idLength;
int firstTextLength = 13;
int serialStart = firstTextStart + firstTextLength;
int serialLength = 10;
int descriptionStart = serialStart + serialLength;

var verboseSplit = input.Split('\n').Select(s => new {
    Id = s.Substring(idStart, idLength),
    FirstText = s.Substring(firstTextStart, firstTextLength),
    Serial = s.Length > descriptionStart
               ? s.Substring(serialStart, serialLength)
               : s.Substring(serialStart) 
    Description = s.Length > descriptionStart 
                    ? s.Substring(descriptionStart) 
                    : String.Empty
});

来自任一的输出:

Id FirstText     Serial     Description 
1  TESTAAA       SERNUM     A DESCRIPTION

2  TESTBBB       ANOTHR     ANOTHER DESCRIPTION

3  TESTXXX       BLAHBL   
于 2013-10-29T04:27:57.383 回答
2

根据您的示例试试这个,每个项目之间有一个空格

{id} {firsttext} {serialhere} {description}
 4    22          6            30+

string target = "1    TESTAAA                SERNUM A DESCRIPTION";
List<string> result = new List<string>(Regex.Split(target, @"(.{4})(.{1})(.{22})(.{1})(.{6})(.{1})(.+)?", RegexOptions.Singleline));
于 2013-10-29T04:36:31.910 回答
1

这种功能性方法怎么样?

从这些数组开始:

var lines = new []
{
    "1 TESTAAA      SERNUM    A DESCRIPTION",
    "2 TESTBBB      ANOTHR    ANOTHER DESCRIPTION",
    "3 TESTXXX      BLAHBL",
};

var splits = new [] { 2, 13, 10, };

splits我使用的与您的问题不同,因为每个示例行中的字段长度与您的拆分不匹配。

现在定义一个递归函数来分割每一行:

Func<string, IEnumerable<int>, IEnumerable<string>> f = null;
f =
    (t, ns) =>
    {
        if (ns.Any())
        {
            var n = ns.First();
            var i = System.Math.Min(n, t.Length);
            var t0 = t.Substring(0, i);
            var t1 = t.Substring(i);
            return new [] { t0.Trim(), }.Concat(f(t1, ns.Skip(1)));
        }
        else
            return new [] { t.Trim(), };
    };

最后,我们可以编写一个相当简单的 linq 查询来将它们组合在一起:

var query =
    from line in lines
    let fields = f(line, splits).ToArray()
    select new
    {
        id = fields[0],
        firsttext = fields[1],
        serialhere = fields[2],
        description = fields[3],
    };

我得到的结果是:

结果

于 2013-10-29T11:49:43.433 回答