Sam Jacobs
Sam Jacobs

Reputation: 346

What is the regex for checking string A for the presence of any 3 consecutive characters in string B?

For example: I have a username string: "[email protected]"

I want to search some password string to make sure it doesn't contain any 3 consecutive letters in the username, e.g.: no "joh", "ohn", "hnw", etc...

I'm aware of a functional way to do this, but is there a way to do this with regex?

Upvotes: 1

Views: 486

Answers (4)

Stefano Sanfilippo
Stefano Sanfilippo

Reputation: 33076

Short answer: no, you should do this in your application code by generating all the 3-letter substrings and checking if the password contains any of them.

But if you feel adventurous, you could still summon a bloody regex monster from a 19th century gothic novel to achieve this.

See @sln's and @Floris's answers for that.

My 2cents: that's a very, very bad idea. Regex are great when you have a fixed, regular syntactical structure to recognize, which is not your case.

Upvotes: 4

Floris
Floris

Reputation: 46435

Heavily inspired by @sln's answer, I would like to offer the following solution:

First - concatenate your user name and password into a single string, separated by a newline (assuming that newline does not otherwise occur in either user name or password; reasonable assumption, I think).

Next, test the resulting string with the following expression:

(?=(...).*\n.*\1)

(See it at work here)

How this works:

(?=   )    - positive lookahead: "somewhere we can match this"
(...)      - three consecutive characters - 'capture group'. We can refer to these as \1
.*\n       - followed by "anything" up to a newline character
.*\1       - followed by "anything" up to a repeat of the first match (the ...)

This is going to try as hard as it can to find a match (that's what regex tries to do). If it succeeds, it means that there was a repeat of three consecutive characters that occurred before the \n in the part after the \n. So try to test for the above; if it succeeds, your "rule" was violated.

edit - example of complete (tested, working) Java code:

import java.io.*;
import java.util.regex.Pattern;
import java.util.regex.Matcher;

class passwordTester
{
    public static void main (String[] args) throws java.lang.Exception
    {
        String username="[email protected]";
        String password = "youcantmakethisup";
        String input = username + "\n" + password;
        System.out.println("testing " + input);
        Pattern p = Pattern.compile("(?=(...).*\\n.*\\1)");
        Matcher m = p.matcher(input);
        if(m.find()) {
          System.out.println("the three character sequence '" + input.substring(m.start(), m.start()+3)+ "' was repeated");
        }
        else System.out.println("the password is good");
    }
}

Output:

testing [email protected]
youcantmakethisup
the three character sequence 'ake' was repeated

Upvotes: 1

user557597
user557597

Reputation:

Capture 3, consume 1
Taking a guess. Catenate username + newline + password.
(atually not a guess)
Context: NO Dot-All
If a match, then error.

 # [email protected]\nPassword
 # (?=(...)[^\n]*\n(?:(?!\1).)*\1)


 (?=                # Lookahead assertion start
      ( . . . )          # Capture 3 non-newline chars
      [^\n]* \n          # Get up to and the next newline
      (?:                # Cluster group start
           (?! \1 )           # Backref check, not the current 3 char string in front of us
           .                  # This char is ok, consume it in the assertion context
      )*                 # Cluster group end, do 0 to many times
      \1                 # Here, found a user name sub-string 
                         #   in the password, it will match now
 )                  # Lookahead assertion end

Upvotes: 1

TypeIA
TypeIA

Reputation: 17258

I don't think so. Regular expressions don't have "memory" and doing what you want requires memory of previously-matched characters. This might be possible with some of the more evil Perl extensions to regular expressions (inline code?), I'm not sure, but I don't believe this is possible with "pure" regular expressions.

Upvotes: 0

Related Questions