-2

The rules for this test are:

  1. Must contain letters and numbers
  2. May contain these special characters anywhere within the string:
Number sign (#)
Minus (-)
Full stop (.)
Slash (/)
Space ( )
  1. May not contain any other special characters
  2. May not consist of only letters
  3. May not consist of only letters and/or the special characters
  4. May not consist of only numbers
  5. May not consist of only numbers and/or the special characters
  6. The numbers, letters and special characters may be in any order

Examples of desired matches:

445b
apt 445a
Apt. #445
Apt 445
Apt-445
Apt - 445
apt445
apt#445
apt/445
APT-445a
APT - 445c
Apt# 445b
Apt. #445-c
22 Elm St.

Examples of non-matches:

apt four forty five
Elm St.
Elm St
Elm Street
445
445 445
445-445
#445
(any or all of the special characters by themselves)

41686d6564's answer below is extremely close but in my original question I failed to specify that spaces are part of the special characters:

/^(?=.*[A-Za-z])(?=.*\d)[A-Za-z0-9\-#\.\/]+$/

I've tried on my own to get the space special character incorporated but I don't get the desired outcome.

See the live example. Live Example

  • 1
    Sorry, but *Must be a mix of alpha and numeric characters* and *May contain the special characters shown inside these parenthesis* are contradictory. So, the first requirement can be crossed out, right? Next, *The string may start with the special characters*, what about the end of string? – Wiktor Stribiżew Feb 11 '21 at 22:17
  • 1
    If both letters and digits must be present (even when special characters are used), and if the special characters can appear anywhere (you didn't state otherwise), you may use `^(?=.*[A-Za-z])(?=.*\d)[A-Za-z0-9\-#.\/]+$` ([demo](https://regex101.com/r/47c3iz/1)). If that's not what you need, you should [edit] the question and clarify the rules. – 41686d6564 stands w. Palestine Feb 11 '21 at 22:23

2 Answers2

1

This regex validates your rules:

/^(?=.*[A-Za-z])(?=.*\d)(?!.*[^A-Za-z0-9\-#\.\/])/

Explanation:

  • ^ - start of string
  • (?=.*[A-Za-z]) - positive lookahead for at least one alpa char
  • (?=.*\d) - positive lookahead for at least one digit char
  • (?!.*[^A-Za-z0-9\-#\.\/]) - negative lookahead for any not allowed char

Instead of the double negative you could use a pattern looking for all valid chars until end of string:

/^(?=.*[A-Za-z])(?=.*\d)[A-Za-z0-9\-#\.\/]*$/

UPDATE based on updated requirement to allow spaces:

/^(?=.*[A-Za-z])(?=.*\d)(?!.*[^A-Za-z0-9\-#\.\/ ])/

Explanation: Simply add a space to the negated character class

Alternatively, look for all valid chars, including space:

/^(?=.*[A-Za-z])(?=.*\d)[A-Za-z0-9\-#\.\/ ]*$/

UPDATE, with JavaScript tests:

const tests = `445b
apt 445a
Apt. #445
Apt 445
Apt-445
Apt - 445
apt445
apt#445
apt/445
APT-445a
APT - 445c
Apt# 445b
Apt. #445-c
22 Elm St.
apt four forty five
Elm St.
Elm St
Elm Street
445
445 445
445-445
#445`;
var regex = /^(?=.*[A-Za-z])(?=.*\d)(?!.*[^A-Za-z0-9\-#\.\/ ])/;
tests.split(/[\r\n]+/).forEach((str) => {
  result = regex.test(str);
  console.log(str + ' ==> ' + result);
});
Peter Thoeny
  • 7,379
  • 1
  • 10
  • 20
  • Peter, I updated the question as I forgot to specify that 'spaces' are part of the special characters allowed. How does this effect your answer? The second part of your answer is what I have currently. When I add \s to the last section it basically allows almost anything to pass. – Bryan Spearman Feb 12 '21 at 03:47
  • I added a JavaScript code snippet, now that you stated that you use JavaScript. In the future, please state your question with details so that we can help better. – Peter Thoeny Feb 12 '21 at 04:15
  • My apologies. I'm new to asking questions here and it took a minute to get the question just right. Thank you for the thorough response! – Bryan Spearman Feb 12 '21 at 14:27
0

It sounds like you're trying to validate if a given string matches a set of password rules, right? I suggest that you don't use a single regex. Here's how I would write it in Perl, but this should be applicable to any language:

# Must be all letters, digits or some punctuation.
if ( $str =~ /^[-#./A-Za-z0-9]+$/ ) {
    $ok = 1;
}
else {
    $ok = 0;
}

# If it is entirely letters, it is bad.
if ( $str =~ /^[A-Za-z]+$/ ) {
    $ok = 0;
}

# If it is entirely digits, it is bad.
if ( $str =~ /^[0-9]+$/ ) {
    $ok = 0;
}

That covers all your rules. It is more lines of code than matching against one hard-to-read regex, but it's much easier for you to understand, and to modify in the future.

You're going to wrap that in a function called something likeis_password_valid, so it doesn't matter if it takes up 20 lines.

Andy Lester
  • 91,102
  • 13
  • 100
  • 152
  • 1
    Thanks Andy I appreciate this very much. Actually this is an address field and the rules are from another department in my company. The form is a a semi-internal form so it's not really public facing. I'm validating the field in JS but I can definitely adopt your Perl code to that. – Bryan Spearman Feb 11 '21 at 22:55