根据指定的格式

时间:2015-09-16 14:58:51

标签: c# asp.net asp.net-mvc

我正在从文本文件中读取行。每条线都是管道分开的。我想验证该行,即每个项目按分隔符分割后按照指定的格式。例如: - 这是我的行

D|111111|87654321|Bar|BCreace|GBP|24/08/2010

检查上述行是否遵循以下格式,例如:

Field Ref Field Length  
S0          1
S1          6
S2          34
...
S6          10

目前我正在使用if条件如下:

    var sortCode = 0;
    if (!int.TryParse(items[1], out sortCode) || items[1].Length > 6)
        errorMessage.Add("Sort Code", "Invalid sort code");

但如果可以以适当的方式完成,有人可以帮助我吗?

由于

4 个答案:

答案 0 :(得分:1)

sortCode初始化为0是多余的,因为编译器可以保证out参数由TryParse函数初始化...并且默认值为无论如何,int值类型为0。

所以不要这样:

var sortCode = 0;

你可以这样:

int sortCode;
if (!int.TryParse(items[1], out sortCode) || items[1].Length > 6)

6这里是一个神奇的数字,最好使它成为一个有意义名称的常量。此外,可能有点过多的逻辑塞进那一行。怎么样?

var parsed = int.TryParse(items[1], out sortCode);
if (!parsed || items[1].Length > SORTCODE_LENGTH)
{
    errorMessage.Add("Sort Code", "Invalid sort code");
}

根据上下文,抛出异常可能是一个更好的想法 - 如果你的方法比你所展示的更多,它可能做了太多事情并且可以从另一个抽象级别中受益。

请注意if下的显式范围 - 有关隐式范围可能发生的情况的示例,请尝试搜索" Apple SSL goto failed" ; - )

如果这是您正在寻找的答案,则需要尝试Code Review

答案 1 :(得分:1)

没有一种正确的方法可以做到这一点,但我建议您使用自定义属性。

我将其命名为ColumnInfoAttribute

class ColumnInfoAttribute : Attribute
{
    public int Index { get; set; }
    public int MaxLength { get; set; }
}

它允许您指定字段的索引和最大长度,以便您可以应用它应该接收值的所有属性:

class LineItem
{
    [ColumnInfo(Index = 0, MaxLength = 1)]
    public string S0 { get; set; }

    [ColumnInfo(Index = 1, MaxLength = 6)]
    public string S1 { get; set; }

    [ColumnInfo(Index = 2, MaxLength = 34)]
    public string S2 { get; set; }

    [ColumnInfo(Index = 3, MaxLength = 34)]
    public string S3 { get; set; }

    [ColumnInfo(Index = 4, MaxLength = 34)]
    public string S4 { get; set; }

    [ColumnInfo(Index = 5, MaxLength = 34)]
    public string S5 { get; set; }

    [ColumnInfo(Index = 6, MaxLength = 34)]
    public DateTime S6 { get; set; }

    public static LineItem Parse(string line)
    {
        var propertyDictionary =
            typeof(LineItem)
            .GetProperties(BindingFlags.Instance | BindingFlags.Public)
            // create an anonymous object to hold the property and the ColumnInfo
            .Select(p => new
            {
                Property = p,
                ColumnInfo = p.GetCustomAttribute<ColumnInfoAttribute>()
            })
            // get only those where the ColumnInfo is not null (in case there are other properties)
            .Where(ci => ci.ColumnInfo != null)
            // create a dictionary with the Index as a key
            .ToDictionary(ci => ci.ColumnInfo.Index);

        var result = new LineItem();

        var values = line.Split('|');
        for (var i = 0; i < values.Length; i++)
        {
            // validate the length of the value
            var isValidLength = values[i].Length > propertyDictionary[i].ColumnInfo.MaxLength;
            if (!isValidLength)
            {
                // todo: throw some appropriate exception or do other error handling
            }

            // set the corresponding property
            var converterdValue = Convert.ChangeType(
                values[i], 
                propertyDictionary[i].Property.PropertyType);
            propertyDictionary[i].Property.SetValue(result, converterdValue);
        }
        return result;
    }
}

同一个类还有一个Parse方法,通过反射获取具有ColumnInfo属性的所有属性并创建一个字典。字典的关键是Index

现在,您可以循环覆盖所有值,并使用i获取ColumnInfo。然后检查字段的长度是否有效,如果是,则使用property.SetValue为属性分配值。

用法:

var line = "D|111111|87654321|Bar|BCreace|GBP|24/08/2010";
var lineItem = LineItem.Parse(line);

它易于扩展且非常通用。如果您有更多此类情况,可以将此代码放在基类中,并将属性添加到派生类中。

答案 2 :(得分:0)

这可能性能稍差,但我发现它更容易阅读和维护。 您可以将该行解析为强类型对象,然后验证该对象。 在下面的示例中,我使用FluentValidation

public class LineItem
{
    public static LineItem Parse(string line)
    {
        var split = line.Split('|');
        return new LineItem(split[0], split[1], split[2], split[3], split[4], split[5], split[6]);
    }

    public LineItem(string s0, string s1, string s2, string s3, string s4, string s5, string s6)
    {
        //any param value checks

        S0 = s0;
        S1 = s1;
        S2 = s2;
        S3 = s3;
        S4 = s4;
        S5 = s5;
        S6 = s6;
    }

    public string S0 { get; set; }
    public string S1 { get; set; }
    public string S2 { get; set; }
    public string S3 { get; set; }
    public string S4 { get; set; }
    public string S5 { get; set; }
    public string S6 { get; set; }
}

public class LineItemValidator : AbstractValidator<LineItem>
{
    public LineItemValidator()
    {
        RuleFor(line => line.S0).Length(1);
        RuleFor(line => line.S2).Length(6);
        //etc
    }
}

然后使用会是这样的:

public class FileValidatorTests
{
    [Fact]
    public void Spike()
    {
        var line = "D|111111|87654321|Bar|BCreace|GBP|24/08/2010";
        var lineItem = LineItem.Parse(line);
        var result = new LineItemValidator().Validate(lineItem);
        Assert.True(result.IsValid);
    }
}

答案 3 :(得分:-1)

正则表达式怎么样?

[^|]\|[^|]{6}\|[^|]{8}\|[^|]{3}\|[^|]{7}\|[^|]{3}\|[^|]{10}

在这里试试https://regex101.com/r/rI6zN6/1