using System.Text.RegularExpressions;
正则表达式认可的特殊字符有:
. * [ ] ^ $ { } + ? | ( )
^ $的意思是对应的表示从这里开始^到$部分结束;
(?:pattern) 表示将pattern部分组合成一个可统一操作的组合项;
?重复是一个次或者0次
常用判断
IsMatch
/// <summary>
/// 验证字符串是否匹配正则表达式规则
/// </summary>
/// <param name="txt">待验证字符串</param>
/// <param name="pattern">正则表达式字符串</param>
/// <param name="bIgnoreCase">匹配时是否不区分大小写(默认不区分大小写)</param>
/// <param name="bValidateWhiteSpace">是否验证空白字符串(默认不验证)</param>
/// <returns></returns>
bool IsMatch(string txt, string pattern, bool bIgnoreCase = false, bool bValidateWhiteSpace = false)
{
// 不验证空白字符串而待验证字符串为空白字符串,则不匹配
if (!bValidateWhiteSpace && string.IsNullOrWhiteSpace(txt))
{
return true; // 放过
}
System.Text.RegularExpressions.Regex reg = null;
if (bIgnoreCase)
{
reg = new Text.RegularExpressions.Regex(pattern, Text.RegularExpressions.RegexOptions.IgnoreCase);
}
else
{
reg = new Text.RegularExpressions.Regex(pattern);
}
return reg.IsMatch(txt);
}
IP
IP: (0-255).(0-255).(0-255).(0-255)
@"^(?: (?: (25[0-5])|(2[0-4]d)|((1d{2})|([1-9]?d))).){3}(?:(25[0-5])|(2[0-4]d)|((1d{2})|([1-9]?d)))$";
@"(?: (?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]).){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9])";
字符 ^ 和 $ 同时使用时,表示精确匹配
URL
@"[w]+://[ ^ /s?#]+[ ^ s?#]+(?:?[ ^ s#])?(?:#[^s])?"
@"[w.+-]+@[w.-]+.[w.-]+"
文件路径
@" ^ ([a-zA-Z]:)?[^/: *?""<>|,]*$"
文件路径中不允许的特殊字符
@" ^ [^/: *?""<>|,]+$"
System.IO.Path.GetInvalidPathChars()
Point / GPS
@"^-?[0-9].?[0-9]+,-?[0-9].?[0-9]+$"
非零的正整数
@"^ [1-9]d*$"
非负数
@"^d*$"
纯中文
@"^ [u4e00-u9fa5]*$"
空格
@"s+"
s匹配任意的空白符,包括空格,制表符(tab),换行符,中文全角空格。
空格和非法字符
~!¥……()——+《》?·,。、;‘【】$^()[]
@"([ ]+)|([~]+)|([!]+)|([¥]+)|([……]+)|([(]+)|([)]+)|([——]+)|([+]+)|([《]+)|([》]+)|([?]+)|([·]+)|([,]+)|([。]+)|([、]+)|([;]+)|([‘]+)|([【]+)|([】]+)|([$]+)|([^]+)|([(]+)|([)]+)|([[]+)|([]]+)"
后端字符串验证
public partial class UserControl1 : UserControl, IUserControlValidate
{
private void ButtonOk_Click(object sender, RoutedEventArgs e)
{
if (!CheckData())
{
return;
}
// TODO
}
public bool CheckData()
{
if (!this.IsValid())
{
Console.WriteLine("数据错误!");
return false;
}
if (!PageValidate.VerifyStringFormat(str, "IP地址", Regex_IP, Regext_Ip_Tip))
{
Console.WriteLine(PageValidate.ErrorMessage);
return false;
}
// ......
return true;
}
}
public static class PageValidate
{
/// <summary>
/// 错误提示
/// </summary>
public static string ErrorMessage { get; set; }
#region 公有
/// <summary>
/// 验证是否符合标准字符串,True符合
/// </summary>
/// <param name="inputTxt">待验证字符串</param>
/// <param name="tipName">验证目标的提示名称</param>
/// <param name="pattern">正则表达式字符串</param>
/// <param name="tipFormatMsg">正确格式的提示信息</param>
/// <returns></returns>
public static bool VerifyStringFormat(string inputTxt, string tipName, string pattern, string tipFormatMsg)
{
ErrorMessage = $"{tipName}不符合指定格式:{tipFormatMsg}!";
return IsMatch(inputTxt, pattern);
}
/// <summary>
/// 判空
/// </summary>
/// <param name="inputTxt">待验证字符串</param>
/// <param name="tipName">验证目标的提示名称</param>
/// <returns></returns>
public static bool VerifyEmpty(string inputTxt, string tipName)
{
if (string.IsNullOrWhiteSpace(inputTxt))
{
ErrorMessage = tipName + "不能为空!";
return true;
}
ErrorMessage = string.Empty;
return false;
}
/// <summary>
/// 整数
/// </summary>
/// <param name="inputTxt">待验证字符串</param>
/// <param name="tipName">验证目标的提示名称</param>
/// <returns></returns>
public static bool VerifyInteger(string inputTxt, string tipName)
{
// 判断效率快于正则
if (string.IsNullOrEmpty(inputTxt) || int.TryParse(inputTxt, out _))
{
ErrorMessage = string.Empty;
return true;
}
ErrorMessage = tipName + "必须是整数!";
return false;
}
/// <summary>
/// 非零的正整数
/// </summary>
/// <param name="inputTxt">待验证字符串</param>
/// <param name="tipName">验证目标的提示名称</param>
/// <returns></returns>
public static bool VerifyPositiveInteger(string inputTxt, string tipName)
{
if (string.IsNullOrEmpty(inputTxt) || (int.TryParse(inputTxt, out int result) && result > 0))
{
ErrorMessage = string.Empty;
return true;
}
ErrorMessage = tipName + "必须是非零的正整数!";
return false;
}
/// <summary>
/// 非负整数(0和正整数)
/// </summary>
/// <param name="inputTxt">待验证字符串</param>
/// <param name="tipName">验证目标的提示名称</param>
/// <returns></returns>
public static bool VerifyNonnegativeInteger(string inputTxt, string tipName)
{
if (string.IsNullOrEmpty(inputTxt) || (int.TryParse(inputTxt, out int result) && result >= 0))
{
ErrorMessage = string.Empty;
return true;
}
ErrorMessage = tipName + "必须是非负整数!";
return false;
}
/// <summary>
/// 浮点数
/// </summary>
/// <param name="inputTxt">待验证字符串</param>
/// <param name="tipName">验证目标的提示名称</param>
/// <returns></returns>
public static bool VerifyFloat(string inputTxt, string tipName)
{
if (string.IsNullOrEmpty(inputTxt) || float.TryParse(inputTxt, out _))
{
ErrorMessage = string.Empty;
return true;
}
ErrorMessage = tipName + "必须是浮点数!";
return false;
}
#endregion
/// <summary>
/// 验证字符串是否匹配正则表达式规则
/// </summary>
/// <param name="txt">待验证字符串</param>
/// <param name="pattern">正则表达式字符串</param>
/// <param name="bIgnoreCase">匹配时是否不区分大小写(默认不区分大小写)</param>
/// <param name="bValidateWhiteSpace">是否验证空白字符串(默认不验证)</param>
/// <returns></returns>
private static bool IsMatch(string txt, string pattern, bool bIgnoreCase = false, bool bValidateWhiteSpace = false)
{
// 不验证空白字符串而待验证字符串为空白字符串,则不匹配
if (!bValidateWhiteSpace && string.IsNullOrWhiteSpace(txt))
{
return true; // 放过
}
System.Text.RegularExpressions.Regex reg = null;
if (bIgnoreCase)
{
reg = new System.Text.RegularExpressions.Regex(pattern, System.Text.RegularExpressions.RegexOptions.IgnoreCase);
}
else
{
reg = new System.Text.RegularExpressions.Regex(pattern);
}
return reg.IsMatch(txt);
}
}
/// <summary>
/// 页面验证接口
/// </summary>
public interface IUserControlValidate
{
/// <summary>
/// 检验相关数据合法性
/// </summary>
/// <returns></returns>
bool CheckData();
}
前端特殊类型验证
比如TextBox的Text是字符串形式,如果绑定其他类型(int等),在输入特殊字符串时会因为转换失败,相应属性还会保留以前的正确值,而TextBox展示与属性不一致。
当输入是空字符串时,后台属性是合法的int值,且提示不友好。
此时后端验证就太晚了,且错误转换的属性无法通过绑定对象进行验证(压根没有转换,还是合法值,只会略过后端验证),需要进行前端验证。
xmlns:util="clr-namespace:XXX.Utility"
<TextBox>
<TextBox.Text>
<Binding Path="PropertyName1">
<Binding.ValidationRules>
<util:NotNullValidationRule/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
using System.Globalization;
using System.Windows.Controls;
/// <summary>
/// 不能为空验证
/// </summary>
internal class NotNullValidationRule : ValidationRule
{
public NotNullValidationRule()
{
ValidatesOnTargetUpdated = true;
}
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
if (value is string val)
{
if (string.IsNullOrWhiteSpace(val))
{
return new ValidationResult(false, "不能为空!");
}
}
return ValidationResult.ValidResult;
}
}
using System.Windows;
using System.Windows.Controls;
/// <summary>
/// 验证依赖对象绑定的数据是否合法
/// true合法,false不合法
/// </summary>
/// <param name="instance"></param>
/// <returns></returns>
public static bool IsValid(this DependencyObject instance)
{
return !Validation.GetHasError(instance) &&
LogicalTreeHelper.GetChildren(instance).OfType<DependencyObject>().All(child => child.IsValid());
}
数据类型对象验证
XAML
<TextBox Text="{Binding IntegerPara, ValidatesOnDataErrors=True, NotifyOnValidationError=True, ValidatesOnExceptions=True}">
<TextBox.Style>
<Style TargetType="TextBox">
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="ToolTip" Value="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=(Validation.Errors)/ErrorContent}"/>
</Trigger>
</Style.Triggers>
</Style>
<TextBox.Style>
<TextBox>
数据类型
public partial class DemoEntity : ValidEntityBase
{
private int _integerPara;
/// <summary>
/// 具体整数参数1
/// </summary>
public int IntegerPara
{
get => _integerPara;
set => UpdateProperty(ref _integerPara, value);
}
private string _stringPara;
/// <summary>
/// 具体字符串参数2
/// </summary>
public string StringPara
{
get => _stringPara;
set => UpdateProperty(ref _stringPara, value);
}
/// <summary>
/// 待验证的属性关联的元数据类
/// </summary>
private class DemoEntity_Metadata
{
[Display(Name = "具体整数参数1")]
[Required(ErrorMessage = "{0} 不能为空!")]
[Range(10, 65535, ErrorMessage = "{0} 必须在10-65525之间!")]
public int IntegerPara { get; set; }
[Display(Name = "具体字符串参数2")]
[Required(ErrorMessage = "{0} 不能为空!")]
[StringLength(255, ErrorMessage = "{0} 输入字符串过长!")]
[RegularExpression(@"[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+.[A-Za-z]{2,4}", ErrorMessage = "{0} 指定格式不正确!!!")]
[CustomValidation(typeof(CustomValidataionUtils), "CustomValidate1")]
public string StringPara { get; set; }
}
public override string this[string columnName] => ValidateProperty<DemoEntity_Metadata>(this, columnName);
}
验证基类
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
/// <summary>
/// 待验证实体基类
/// </summary>
public partial class ValidEntityBase : NotifyPropertyChangedEx, IDataErrorInfo
{
public virtual string this[string columnName] => string.Empty;
public string Error => null;
/// <summary>
/// 验证属性
/// </summary>
/// <typeparam name="MetadataType"></typeparam>
/// <param name="obj">属性所属对象</param>
/// <param name="propertyName">属性名称</param>
/// <returns></returns>
internal string ValidateProperty<MetadataType>(object obj, string propertyName)
{
if (string.IsNullOrEmpty(propertyName))
{
return string.Empty;
}
Type targetType = obj.GetType();
if (targetType != typeof(MetadataType))
{
TypeDescriptor.AddProviderTransparent(new AssociatedMetadataTypeTypeDescriptionProvider(targetType, typeof(MetadataType)), targetType);
}
object propertyValue = targetType.GetProperty(propertyName).GetValue(obj, null);
ValidationContext validationContext = new ValidationContext(obj, null, null)
{
MemberName = propertyName
};
List<ValidationResult> validationResults = new List<ValidationResult>();
_ = Validator.TryValidateProperty(propertyValue, validationContext, validationResults);
return validationResults.Count > 0 ? validationResults.First().ErrorMessage : string.Empty;
}
}
验证
private void Button_Click(object sender, RoutedEventArgs e)
{
if (!this.IsValid())
{
var btn = (Button)sender;
btn.CommandParameter = false;
MessageBox.Show("ERROR!");
// MVVM 可在ViewModel里提示验证错误信息
}
}
其他复杂验证集合
public class CustomValidataionUtils
{
public static ValidationResult CustomValidate1(string value)
{
// TODO
return ValidationResult.Success;
}
}