我正在从文本文件中读取行。每条线都是管道分开的。我想验证该行,即每个项目按分隔符分割后按照指定的格式。例如: - 这是我的行
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");
但如果可以以适当的方式完成,有人可以帮助我吗?
由于
答案 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}