ap_go
ap_go

Reputation: 69

How do I match a pattern with alphabets AND numbers, but not if it contains only alphabets?

I'm trying to use regex that checks a string for alphabets and numbers, but it shouldn't match if the string contains only alphabets. This is for a javascript code. Should lookahead be used?

Should match: 1234567 a1b2c3d4e5 1a2b3c4d5e

Should not match: abcdefg

EDIT: Thanks to @balsick this question has been answered. Here's the regex to be used - (([a-zA-Z0-9]+\d+[a-zA-Z0-9])|(\d+[a-zA-Z0-9]+\d))+

I do have a follow-up question: can a length constraint be added to this regex? For example: I want to match only strings that are 10-20 alphabets/digits.

Upvotes: 1

Views: 1067

Answers (3)

The fourth bird
The fourth bird

Reputation: 163362

You could assert the start of the string ^, use a non capturing group (?: with an alternation to match either a digit \d or | one or more characters followed by a digit [a-z]+\d. This makes sure that you have at least 1 digit and that you could also start with characters.

Then for the last part of the regex you could match zero or more digits and characters [a-z\d]* until the end of the string $.

To match upper and lowercase characters you could use [a-z] with the case insensitive flag /i

^(?:\d|[a-z]+\d)[a-z\d]*$

let pattern = /^(?:\d|[a-z]+\d)[a-z\d]*$/i;
const strings = [
  "a1b2c3d4e5",
  "1a2b3c4d5e",
  "abcdefg",
  "1234567"
];
strings.forEach((s) => {
  console.log(s + " ==> " + pattern.test(s));
});

If you want to make sure that your match contains 10 - 20 alphanumeric characters you could use a positive lookahead:

^(?=[a-z\d]*\d)[a-z\d]{10,20}$

let pattern = /^(?=[a-z\d]*\d)[a-z\d]{10,20}$/i;
const strings = [
  "a1b2c3d4e5",
  "1a2b3c4d5e",
  "1234567",
  "abcdefg",
  "1234567",
  "12112121121fffdfdfdfdfdfdfd",
  "fdfddfdfdffdfdf5ffrtgr54f345f453f3ff"
];
strings.forEach((s) => {
  console.log(s + " ==> " + pattern.test(s));
});

Upvotes: 2

rweisse
rweisse

Reputation: 830

Try this:

((\w+\d+\w*)|(\d+\w+\d*))+

\w looks for alphabetic

\d looks for digits

+ means at least one

* means zero or more

| is the or operator

EDIT (Improvement)

I have found a better solution for your primary question. It is shorter and faster than the solution of @balsick and it won't catch the _ character:

([a-zA-Z]*\d[a-zA-Z]*)+

Your wish to limit the length of strings is hard to conquer with regex. There are options to limit the number of matches. For example with:

a{5}, a{2,} exactly five, two or more

a{1,3} between one & three

But this won't work with the upper regex, because each single submatch will be either

  • one or more letters in combination with a number like: aa1,
  • a number in combination with one or more letters like: 1aaa,
  • one or more letters in combination with a number and one or more letter like: a1aa
  • or a single number like: 1

If you have an match like a1b2c3d4e5 it consists out of these submatches: a1b 2c 3d 4e 5

Although the match consists out of 10 characters, using the quantifier {10,20} instead of the last plus sign won't work, because the real number of submatches would be 5 and not 10.

I think you have to use the upper regex and after that check the length of each match programatically afterwords.

Pseudo code:

foreach (var match in matches) {
    if (match.Value.length < 21 && match.Value.length > 9) {
        doSomething();
    }
}

Or if you have the possibility to use Linq you could do something like this:

var filteredMatches = matches.Filter(match => match.Value.length < 21 && match.Value.length > 9)

Upvotes: 4

Matt.G
Matt.G

Reputation: 3609

Answer updated with input from @balsick

Using lookahead Regex:

^(?=[A-Za-z\d]*\d)[A-Za-z\d]*$

Demo

Upvotes: 0

Related Questions