根据指定格式验证管道分隔行
本文关键字:管道 隔行 验证 格式 定格 | 更新日期: 2023-09-27 18:13:11
我正在从文本文件中读取行。每一行都是管道分隔的。我想验证行,即每个项目是根据指定的格式后分割分隔符。-这是我的台词
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");
但是谁能帮助我,如果这可以在一个适当的方式?
谢谢
没有一个正确的方法来做到这一点,但我有一个建议,你使用自定义属性。
我把它命名为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
。
现在您可以对所有值进行for循环,并使用i
来获得ColumnInfo
。然后检查字段的长度是否有效,如果有效,则使用property.SetValue
为该属性赋值。
用法:
var line = "D|111111|87654321|Bar|BCreace|GBP|24/08/2010";
var lineItem = LineItem.Parse(line);
它易于扩展并且非常通用。如果您有更多这样的情况,您可以将此代码放在基类中,并将属性添加到派生类中。
将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 fail";-)
如果这是你正在寻找的答案,你需要尝试Code Review。
这可能性能不太好,但我发现它更容易阅读和维护。您可以将该行解析为强类型对象,然后验证该对象。在下面的例子中,我使用的是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);
}
}
正则表达式呢?
[^|]'|[^|]{6}'|[^|]{8}'|[^|]{3}'|[^|]{7}'|[^|]{3}'|[^|]{10}
在这里试试https://regex101.com/r/rI6zN6/1