我正在尝试创建一个正则表达式来验证应该在 -12.0到+13.0 范围内的字段(十进制)。
我能够执行此正则表达式^[-+]?(?:[0-9]|[0-1][0-2](?:[.][0-9])?)$
,但这还不够,因为这将允许-12.9到+12.9值,并且不会验证0或0.0之类的内容。
我知道这不是最好的解决方案,更好的方法是使用模型并使用Data Annotation添加正则表达式验证。
这里的主要问题是Model.Value是一个字符串。但是我需要在更新数据库值之前以许多不同的方式验证字符串。我验证该字符串的方法是使用一个外键来告诉我要使用的正则表达式。
想象一下这个模型。
MODELA
public virtual int Id{ get; set; }
public virtual IList<ModelB> ModelB{ get; set; }
模型B
public virtual string Value { get; set; }
public virtual DataType DataType{ get; set; }
在DataType中,我对该特定值进行了正则表达式验证
这就是我使用这种方法的原因......
有人能帮助我做到这一点吗?
感谢您的帮助。
答案 0 :(得分:2)
对于这样的目标,我会在几个较小的问题中解决问题,然后考虑合并它们以制作更简单的正则表达式。
第一个负数:(-(12(\.0*)?|(1[01]|\d)(\.\d*)?|\.\d+)
-( # Always have a minus sign, then three alternatives.
12(\.0*)? # It can be `12` or `-12.` or `-12.000000`.
| (1[01]|\d) # It can be a `10` or a `11` or any single digit,
(\.\d*)? # optionally followed by a fractional part.
| \.\d+ # It can be just a fractional part.
)
零和正数几乎相同。 +
是可选的,13
是特例,两位数集现在包含12
因此:\+?(13(\.0*)?|(1[012]|\d)(\.\d*)?|\.\d+)
然后我们可以将这两个表达式组合起来作为替代,给出:
((-(12(\.0*)?|(1[01]|\d)(\.\d*)?|\.\d+))|(\+?(13(\.0*)?|(1[012]|\d)(\.\d*)?|\.\d+)))
这有很多不感兴趣的捕获。它们都可以是非捕获的,但表达式更简单,没有额外的?:
个字符。但是在这个阶段添加它们是很好的。导致:
^((?:-(?:12(?:\.0*)?|(?:1[01]|\d)(?:\.\d*)?|\.\d+))|(?:\+?(?:13(?:\.0*)?|(?:1[012]|\d)(?:\.\d*)?|\.\d+)))$
关于前导零的处理的问题尚不清楚,即是否包括或排除-00011.9
和000.0001
和+012.3
等值。如果允许前导零,则在0*
或-
之后添加+
。还更改了\d
以匹配单个数字到[1-9]
,以避免关于例如单个前导零的位置的模糊性。 0.123
应该匹配。最后的表达是:
((?:-0*(?:12(?:\.0*)?|(?:1[01]|[1-9])(?:\.\d*)?|\.\d+))|(?:\+?0*(?:13(?:\.0*)?|(?:1[012]|[1-9])(?:\.\d*)?|\.\d+)))
使用正则表达式
在C#中测试,每行选择一个数字,每行一个@"^((?:-0*(?:12(?:\.0*)?|(?:1[01]|[1-9])(?:\.\d*)?|\.\d+))|(?:\+?0*(?:13(?:\.0*)?|(?:1[012]|[1-9])(?:\.\d*)?|\.\d+)))$"
回应评论似乎需求是一个与正则表达式[-+]\d\d?\.\d
匹配且在-12.0 <= number <= +13.0
范围内的数字。
重新处理上面的最后一个正则表达式以满足这些需求提供了以下内容。如果不允许前导+
,则忽略表达式中的\+?
。
((?:-(?:12\.0|(?:1[01]|\d)\.\d))|(?:\+?(?:13\.0|(?:1[012]|\d)\.\d)))
(删除了前导零;将多个小数位更改为单个数字;删除了.\d
选项。)
答案 1 :(得分:2)
由于您正在进行Web客户端验证,因此您无法使用Decimal.Parse()
(或更好Decimal.TryParse()
),但数据注释已经拥有您所需的内容。假设您在ViewModel中有此属性:
public class MyModel {
[RegularExpression("^[-+]?(?:[0-9]|[0-1][0-2](?:[.][0-9])?)$")]
public decimal Value { get; set; }
}
是的,您可能修复此正则表达式,但它们不是处理数值范围验证的最佳工具,表达式将很快变得非常复杂和 - 一般 - 它不容易发展来改变需求(如果你需要验证(-100..+1000.3]
怎么办?)如果正则表达式是你真正需要的(不仅仅是你想要使用的) )然后使用AdrianHHH's answer(并且不要忘记包含用户对十进制分隔符的区域设置处理),如果没有(并且假设您的环境有效),请使用:
public class MyModel {
[Range(typeof(decimal), "-12", "13")]
public decimal Value { get; set; }
}
这就是全部。请注意,如果您使用double
代替decimal
,则可以进一步简化为[Range(-12.0, 13.0)]
。有关详细信息,请参阅MSDN。
编辑:根据您的编辑,您的方案有点复杂但是我仍然建议不要滥用正则表达式,因为这样,正确的方法(数据注释)仍然是一个可行的解决方案。首先,让我们创建一个自定义验证类:
[AttributeUsage(AttributeTargets.Property)]
public class ComplexLogicAttribute: ValidationAttribute, IClientValidatable
{
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var model = (MyModel)validationContext.ObjectInstance;
if (IsValueValidForGivenObject(model, Convert.ToString(value)))
return ValidationResult.Success;
// Or your own error message...
return new ValidationResult(FormatErrorMessage(null));
}
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
var modelClientValidationRule = new ModelClientValidationRule
{
ValidationType = "complexlogic",
ErrorMessage = ErrorMessage
};
return new List<ModelClientValidationRule> { modelClientValidationRule };
}
}
IsValueValidForGivenObject()
骨架在哪里:
private bool IsValueValidForGivenObject(MyModel model, string value)
{
decimal minimum = CalculateMinimumAccordingToVeryComplexLogic(model);
decimal maximum = CalculateMaximumAccordingToMagic(model);
decimal number;
if (!Decimal.TryParse(value, out number))
return false;
if (number < minimum || number > maximum)
return false;
return PerformEvenMoreComplexEsotericValidation(model, number);
}
现在您必须提供客户端验证(请在ComplexLogic.js
中说明,不要忘记包含它):
$.validator.addMethod("complexlogic", function (value, element, params) {
// Repeat your validation logic here!
return true;
});
$.validator.unobtrusive.adapters.add("complexlogic", function (options) {
options.messages["complexlogic"] = options.message;
});
请查看this simple tutorial以获得更好的解释。总而言之,您将数字验证为数字,而且您的代码足够灵活......