如何构造特定的Java regexp
我需要检查一个登录名。它必须(这是政治决定,不是技术决定)具备:如何构造特定的Java regexp,java,regex,Java,Regex,我需要检查一个登录名。它必须(这是政治决定,不是技术决定)具备: 5-30个字符 字符必须来自组[a-zA-Z0-9*] 至少一个字符必须是数字 如果登录名有5个字符,不可能所有字符都来自数字,但如果登录名有6个或更多字符,则可以仅从数字构造 我有regexp(?=[a-zA-Z0-9*]*[0-9])[a-zA-Z0-9*]{5,30}适用于第1-3点,但无法想象如何包含第4点的检查。使用regex 使用一个非常复杂的正则表达式来验证字符串的所有方面总是很诱人的。但请记住,这件事可能很难在
[a-zA-Z0-9*]
李>
(?=[a-zA-Z0-9*]*[0-9])[a-zA-Z0-9*]{5,30}
适用于第1-3点,但无法想象如何包含第4点的检查。使用regex
使用一个非常复杂的正则表达式来验证字符串的所有方面总是很诱人的。但请记住,这件事可能很难在将来扩展和维护 含义:根据验证规则的“更改”率,可能会有更好的设计。例如,我们可以设想如下:
interface NameValidator {
isValid(String name) throws InvalidNameException;
}
class LengthValidator implements NameValidator ...
class XyzValidator implements NameValidator ...
class NameValidation {
private final List validators = Arrays.toList(new LengthValidator(), ...
void isValid(String name) {
run all validators ...
这样,添加/更改一个验证规则。。。变得更加直截了当。。。而不是篡改一个正则表达式,可能破坏它的其他部分
除此之外,您甚至可以构建不同的规则集;通过组合名称验证实现者的不同实例;同时避免代码重复。正如其他人所指出的,您不必使用单个正则表达式。即使这是可能的,它将是令人讨厌的复杂和难以理解的其他人 最简单的方法是最好的:
boolean passwordValid = password.matches("[a-zA-Z0-9*]{5,30}")
&& password.matches(".*[0-9].*")
&& !password.matches("[0-9]{5}");
我想提出一种不同的方法:不要使用正则表达式,而是检查每个字符并收集密码属性。这样,您就能够在以后实现更复杂的需求,例如“它必须有四分之三” 例如:
String pw = "1a!cde";
Set<PwProperty> passwordProperties = new HashSet<>();
for( char c : pw.toCharArray() ) {
if( isDigit( c ) ) {
passwordProperties.add( PwProperty.DIGIT );
}
else if ( isSpecialChar( c ) ) {
passwordProperties.add( PwProperty.SPECIAL);
}
else if( isUpperCase( c ) ) {
passwordProperties.add( PwProperty.UPPER_CASE);
}
else if( isLowerCase( c ) ) {
passwordProperties.add( PwProperty.LOWER_CASE);
}
else {
passwordProperties.add( PwProperty.UNKNOWN );
}
}
String pw=“1a!cde”;
Set passwordProperties=new HashSet();
for(字符c:pw.toCharArray()){
if(isDigit(c)){
passwordProperties.add(PwProperty.DIGIT);
}
else如果(isSpecialChar(c)){
添加(PwProperty.SPECIAL);
}
else if(大写(c)){
passwordProperties.add(PwProperty.UPPER_大小写);
}
else if(小写字母(c)){
添加(PwProperty.LOWER_CASE);
}
否则{
passwordProperties.add(PwProperty.UNKNOWN);
}
}
然后您可以这样检查(伪代码):
如果(!pw.length()在范围内){
显示“密码太短”或“密码太长”
}
if(passwordProperties.contains(PwProperty.UNKNOWN){
显示“使用了不支持的字符”
}
setOf4={数字,特殊,小写,大写}
if(交叉点(passwordProperties,setOf4).size()<3){
显示“至少使用四分之三”
}
如果(!passwordProperties.contains(数字)){
显示“必须包含数字”
}
显示交叉点的“密码强度”(passwordProperties、setOfGoodProperties)。大小()
等
然后可以扩展该属性,例如使用可能不需要的数字\u序列
等属性
主要的优点是,您拥有关于密码的更详细信息,而不是“它是否匹配某个正则表达式”你可以用这些信息来指导用户。如果你只想用Java来做这件事,为什么不使用If/else根据字符数将其分成两个正则表达式呢?从技术上讲,这是可能的,我现在正在尝试改进它……你可以添加一个类似
(?![0-9]{5}$)的外观
@SebastianProske不允许在结尾处有5位数字的序列,但如果密码类似于a12345
?@Thomas您应该在前面添加lookback(类似于另一个),它将允许登录名类似于a12345
,请参阅@SebastianProske看起来像这样,谢谢:)我正在检查,如果您需要在配置中使用正则表达式,应该会有问题file@LadislavDANKO这是真的,这可能是不使用这种方法的一个原因。然而,这意味着提供更大的灵活性,特别是在指导用户方面,并且仍然可以通过允许通过文本文件进行配置的方式来实现。
String pw = "1a!cde";
Set<PwProperty> passwordProperties = new HashSet<>();
for( char c : pw.toCharArray() ) {
if( isDigit( c ) ) {
passwordProperties.add( PwProperty.DIGIT );
}
else if ( isSpecialChar( c ) ) {
passwordProperties.add( PwProperty.SPECIAL);
}
else if( isUpperCase( c ) ) {
passwordProperties.add( PwProperty.UPPER_CASE);
}
else if( isLowerCase( c ) ) {
passwordProperties.add( PwProperty.LOWER_CASE);
}
else {
passwordProperties.add( PwProperty.UNKNOWN );
}
}
if( !pw.length() in range ) {
display "password too short" or "password too long"
}
if( passwordProperties.contains( PwProperty.UNKNOWN ) {
display "unsupported characters used"
}
Set<PwProperty> setOf4 = { DIGIT, SPECIAL, LOWER_CASE, UPPER_CASE }
if( intersection( passwordProperties, setOf4 ).size() < 3 ) {
display "use at least 3 out of 4"
}
if( !passwordProperties.contains( DIGIT ) ) {
display "must contain digits"
}
display "password strength" being intersection( passwordProperties, setOfGoodProperties ).size()
etc.