Câu hỏi này bắt đầu lan truyền và rất nhiều gợi ý thú vị xuất hiện.
Vâng, viết bằng tay rất khó. Vì vậy, một giải pháp dễ dàng hơn là sử dụng một mẫu. Mặc dù kết quả regex có thể không phải là tối ưu nhất, nó sẽ dễ bảo trì và / hoặc thay đổi hơn và người dùng sẽ kiểm soát tốt hơn kết quả. Có thể là tôi đã bỏ lỡ điều gì đó, vì vậy bất kỳ lời phê bình mang tính xây dựng nào cũng sẽ hữu ích.
Các liên kết này có thể thú vị: so khớp ít nhất 2 chữ số 2 chữ cái theo thứ tự bất kỳ trong một chuỗi , Ngôn ngữ biểu thức chính quy , Nhóm nắm bắt
Tôi đang sử dụng mẫu này (?=(?:.*?({type})){({count})})
dựa trên tất cả regex mà tôi đã thấy trong SO. Bước tiếp theo là thay thế mẫu cần thiết ( number
,special character
...) và thêm cấu hình cho độ dài.
Tôi đã tạo một lớp học nhỏ để soạn thảo regex PasswordRegexGenerator.cs
Một ví dụ:
string result = new PasswordRegexGenerator ( )
.UpperCase ( 3, -1 ) // ... {3,}
.Number ( 2, 4 ) // ... {2,4}
.SpecialCharacter ( 2 ) // ... {2}
.Total ( 8,-1 )
.Compose ( );
/// <summary>
/// Generator for regular expression, validating password requirements.
/// </summary>
public class PasswordRegexGenerator
{
private string _elementTemplate = "(?=(?:.*?({type})){({count})})";
private Dictionary<string, string> _elements = new Dictionary<string, string> {
{ "uppercase", "[A-Z]" },
{ "lowercase", "[a-z]" },
{ "number", @"\d" },
{ "special", @"\W" },
{ "alphanumeric", @"\w" }
};
private StringBuilder _sb = new StringBuilder ( );
private string Construct ( string what, int min, int max )
{
StringBuilder sb = new StringBuilder ( _elementTemplate );
string count = min.ToString ( );
if ( max == -1 )
{
count += ",";
}
else if ( max > 0 )
{
count += "," + max.ToString();
}
return sb
.Replace ( "({type})", what )
.Replace ( "({count})", count )
.ToString ( );
}
/// <summary>
/// Change the template for the generation of the regex parts
/// </summary>
/// <param name="newTemplate">the new template</param>
/// <returns></returns>
public PasswordRegexGenerator ChangeRegexTemplate ( string newTemplate )
{
_elementTemplate = newTemplate;
return this;
}
/// <summary>
/// Change or update the regex for a certain type ( number, uppercase ... )
/// </summary>
/// <param name="name">type of the regex</param>
/// <param name="regex">new value for the regex</param>
/// <returns></returns>
public PasswordRegexGenerator ChangeRegexElements ( string name, string regex )
{
if ( _elements.ContainsKey ( name ) )
{
_elements[ name ] = regex;
}
else
{
_elements.Add ( name, regex );
}
return this;
}
#region construction methods
/// <summary>
/// Adding number requirement
/// </summary>
/// <param name="min"></param>
/// <param name="max"></param>
/// <returns></returns>
public PasswordRegexGenerator Number ( int min = 1, int max = 0 )
{
_sb.Append ( Construct ( _elements[ "number" ], min, max ) );
return this;
}
public PasswordRegexGenerator UpperCase ( int min = 1, int max = 0 )
{
_sb.Append ( Construct ( _elements[ "uppercase" ], min, max ) );
return this;
}
public PasswordRegexGenerator LowerCase ( int min = 1, int max = 0 )
{
_sb.Append ( Construct ( _elements[ "lowercase" ], min, max ) );
return this;
}
public PasswordRegexGenerator SpecialCharacter ( int min = 1, int max = 0 )
{
_sb.Append ( Construct ( _elements[ "special" ], min, max ) );
return this;
}
public PasswordRegexGenerator Total ( int min, int max = 0 )
{
string count = min.ToString ( ) + ( ( max == 0 ) ? "" : "," + max.ToString ( ) );
_sb.Append ( ".{" + count + "}" );
return this;
}
#endregion
public string Compose ()
{
return "(" + _sb.ToString ( ) + ")";
}
}