简体   繁体   中英

How to create a single JavaScript regex to match both length and multiple constraints?

I need to build a JavaScript regular expression with the following constraints:

  • The input string needs to be at least 6 characters long
  • The input string needs to contain at least 1 alphabetical character
  • The input string needs to contain at least 1 non-alphabetical character

I'm seriously lacking a lookback feature in JavaScript. The thing I came up with:

((([a-zA-Z][^a-zA-Z])|([^a-zA-Z][a-zA-Z]))....)|
(.(([a-zA-Z][^a-zA-Z])|([^a-zA-Z][a-zA-Z]))...)|
(..(([a-zA-Z][^a-zA-Z])|([^a-zA-Z][a-zA-Z]))..)|
(...(([a-zA-Z][^a-zA-Z])|([^a-zA-Z][a-zA-Z])).)|
(....(([a-zA-Z][^a-zA-Z])|([^a-zA-Z][a-zA-Z])))

This looks pretty long. Is there a better way?

How I came to this:

  1. Regex for alphabetical character is [a-zA-Z]
  2. Regex for non-alphabetical character is [^a-zA-Z]
  3. So I need to look for a [a-zA-Z][^a-zA-Z] or [^a-zA-Z][a-zA-Z]
    so (([a-zA-Z][^a-zA-Z])|([^a-zA-Z][a-zA-Z])) .
  4. I need to check for n preceding characters and 6- n succeeding characters.
/^(?=.{6})(?=.*[a-zA-Z])(?=.*[^a-zA-Z])/

This means:

^ - start of the string
(?= ... ) - followed by (ie an independent submatch; it won't move the current match position)
.{6} - six characters ("start of string followed by six characters" implements the "must be at least six characters long" rule)
.* - 0 or more of any character (except newline - may need to fix this?)
[a-zA-Z] - a letter ( .*[a-zA-Z] therefore finds any string with a letter anywhere in it (technically it finds the last letter in it))
[^a-zA-Z] - a non-letter character

In summary: Starting from the beginning of the string, we try to match each of the following in turn:

  • 6 characters (if we find those, the string must be 6 characters long (or more))
  • an arbitrary string followed by a letter
  • an arbitrary string followed by a non-letter

Use this regex...

/^(?=.{6,})(?=.*[a-zA-Z])(?=.*[^a-zA-Z]).*$/
  -------- ------------- --------------
    ^          ^              ^
    |          |              |->checks for a single non-alphabet
    |          |->checks for a single alphabet
    |->checks for 6 to many characters

(?=) is a zero width look ahead which checks for a match.It doesn't consume characters.This is the reason why we can use multiple lookaheads back to back

Similar answer to others, thus this doesn't need much explanation, I think the best way is to do

/^(?=.*[a-zA-Z])(?=.*[^a-zA-Z]).{6,}$/

This starts at the beginning of the string, looks ahead for an alphabetical character, looks ahead for a non-alphabetical character and, in the end, it finds a string of 6+ chars, I think there's no need for lookaheads about length

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM