views:

301

answers:

8

Hello. I'm having a problem writing a regular expression. How could I write the following:

  1. start with an optional access level (a digit from 1 to 5)
  2. followed by a space
  3. then a user name consisting of between 3 and 5 small letters
  4. followed by between 3 and 5 digits
  5. then one or more spaces
  6. and then a four digit pin number
  7. then one or more spaces
  8. and the same pin again for confirmation..

If the information is valid, display an alert saying "Thank you." Otherwise "The information entered is incorrect."

I wrote the following, but it doesn't work properly:

reg=/^(\d{1,5})?/s ([a-z]{3,5}\b\d{3,5}\s) \s\1 $/;

I would appreciate any help.

A: 

try this: ([1-5])?\s[a-z]{3,5}(\s*\d{4}){2}

Fernando
The input must start with a space if no access levvel is present - I assume this is not the desired behavior. Further you don't verify that both pin numbers are equal.
Daniel Brückner
And \s* makes the space optional while at least one space is required, hence it should be \s+.
Daniel Brückner
Both are true! =D
Fernando
A: 

It sounds like you want the first space, even if no access level is specified? If so, I think this should do the trick:

/^([1-5])? [a-z]{3,5}\d{3,5} +(\d{4}) +\2$/

If the space is optional, just move it inside the first set of parentheses.

To display the alerts, a simple if/else should do it.

John Hyland
I don't think the first one is 1 to 5 digits long. The instructions say "a digit from 1 to 5"
seth
Yeah I doubt it too, but his example and description are contradictory.
annakata
Oops, you're right! Fixed, thanks.
John Hyland
I think the access level together with the space are optional - this expression forces starting with a space if no access level is present, hence ([0-5]_)? instead of ([0-5])?_ or [0-5]?_.
Daniel Brückner
+2  A: 

A few problem I see right away:

\d{1,5} will match any digit (0-9) for 1 to 5 occurrences. ie 0001, 12,3,41332. I think you are looking for [1-5] which will match one digit in the range of 1-5.

/s should be \s

with [a-z]{3,5}\b\d{3,5}\s I am not sure why you have \b there.

Fix these problems first I think. :)

MitMaro
@Jonathan: Thanks for fixing the code, didn't know you could do inline code blocks :)
MitMaro
+4  A: 

Ok, following your instructions to the letter (which I'm not convinced is what you actually want) you can use:

/^[1-5]?\s[a-z]{3,5}\d{3,5}\s+(\d{4})\s+(\1)$/

Breaking this down that's:

  • start of line
  • a single digit between 1 and 5, optionally
  • a space (strictly speaking any whitespace)
  • between 3 and 5 lowercase letters
  • between 3 and 5 digits
  • at least one space
  • exactly 4 digits
  • at least one space
  • the same pattern of 4 digits (the \1 is critical here)
  • end of line

    You've introduced the wrong pattern for the access level, a random word break and failed to capture multiple spaces correctly which is where your pattern breaks down.

annakata
`\s` matches any whitespace (e.g. tab), not just spaces. Otherwise, spot-on.
Vinay Sajip
what does '/^' do? i know ^ is start of line but what is the /? is that just how to do regex in javascript?
Victor
You have a few typos, perhaps an edit is in order.
Nixuz
@Vinay, yes I said as much in the above, but I *suspect* this is more desirable @Victor - / is just startng the regex, cf the same at the end of the expression
annakata
@Nixuz - Fixed some trivial typos, but really nothing worth mentioning - is there something you had in mind?
annakata
"2. followed by a space" indicates that the first space should only be present if the access level is present - starting an input with a spaace seems wrong, doesn't it?
Daniel Brückner
@Daniel - Yep, but it's what he asked for.
annakata
thank you very much for your answer but i have questioin if u never mind/^[1-5]?\s[a-z]{3,5}\d{3,5}\s+(\d{4})\s+(\1)$/first \s we did not put an '+' but we did for the other \swhy??
@think_blue - the first \s is required to match only once but the others are required to match once *or more* so it requires the "+" quantifier
annakata
The first \s forces **ONE and ONLY one** match. think_blue, you should know that \s will match any whitespace which means TAB or SPACE. If you want to limit user to only use space, please replace \s with ' '.
SolutionYogi
I would leave the `\s` though, I mean should it really matter if they used a `tab` instead of '` `'
Brad Gilbert
A: 

Try this one:

^(?:[1-5] )?[a-z]{3,5}\d{3,5} +(\d{4}) +\1$

You might find my regex tool useful for testing regular expressions. It has an "explain" mode that will break an expression down and describe what it does, if you are stuck.

Good luck!

Chris Nielsen
I think the access level together with the space are optional - this expression forces starting with a space if no access level is present, hence ([0-5]_)? instead of ([0-5])?_ or [0-5]?_.
Daniel Brückner
Upon re-reading, I think you must be right. I've edited to fix, but your answer looks better anyway. Thanks!
Chris Nielsen
+4  A: 
^(?:[1-5] )?[a-z]{3,5}[0-9]{3,5} +([0-9]{4}) +\1$

Explanation

    ^            Anchor start of line.
    (?:[1-5] )?  Optional access level 1 to 5 followed by a single space,
                 the group is non-capturing.
    [a-z]{3,5}   User name with 3 to 5 lower case letters followed by
    [0-9]{3,5}   3 to 5 digits.
    _+           At least one space.
    ([0-9]{4})   A 4 digit pin number captured into group \1. Without the
                 non-capturing group from above the pin number would be
                 captured into group \2.
    _+           At least one space.
    \1           A backreference to the pin number captured in group \1.
    $            Anchor end of line.
Daniel Brückner
You didn't use \1 in your regex.
SolutionYogi
Thanks, fixed.
Daniel Brückner
You haven't included the ( ) to capture [0-9]{4} in your regex either.
Nefrubyr
Why is everything in the explanation but not in the regex?!? What's going on?!? :D
Daniel Brückner
A: 

What you are describing is not a regular language, therefore it cannot be parsed by a regular expression. The problem is your requirements 6 and 8: regular expressions don't have memory, therefore it is impossible to check that the PINs in 6 and 8 are identical.

Jörg W Mittag
Of course it's possible, it's called a "backreference".
Pavel Minaev
@Pavel: Joerg is theoretically correct. What any practically useful package implements includes expressions that are not "regular" in the theoretical sense e.g. they use capturing groups and back references to the same. Most folk use "regular expression" in a rather loose sense, and most of the minority don't get agitated about it ;-)
John Machin
There is no such thing as a "backreference" in regular expressions. You might be thinking of Regexps, which sometimes *do* have backreferences (and sometimes don't). But the OP was specifically asking about a "regular expression" and *not* about a Regexp. Those two are totally different things. In particular, Regexps are typically much more powerful than regular expressions.
Jörg W Mittag
@Joerg: The OP said "regular expression", but like 99.99% of OPs and answerers he really meant "Regexps as implemented in some particular programming language or package", and would not know (and doesn't need to know) what a "regular language" is in your lexicon. Get used to it.
John Machin
A: 

Here's a Python answer, showcasing the re.VERBOSE facility, which is very handy if you want to come back tomorrow and understand what your regex is doing.

See this for further explanation. You won't need a vine or rope to swing on. :-)

import re
match_logon = re.compile(r"""
    [1-5]?      # 1. start with an optional access level (a digit from 1 to 5)
    [ ]         # 2. followed by a space
    [a-z]{3,5}  # 3. then a user name consisting of between 3 and 5 small letters
    \d{3,5}     # 4. followed by between 3 and 5 digits
    [ ]+        # 5. then one or more spaces
    (\d{4,4})   # 6. and then a four digit pin number (captured for comparison)
    [ ]+        # 7. then one or more spaces
    \1          # 8. and the same pin again for confirmation..
    $           # match end of string
    """, re.VERBOSE).match
tests = [
    ("1 xyz123    9876    9876", True),
    (" xyz123    9876    9876", True), # leading space? revisit requirement!
    ("0 xyz123    9876    9876", False),
    ("5 xyz123    9876    9876", False), # deliberate mistake to test the testing mechanism :-)
    ("1 xy1234    9876    9876", False),
    ("5 xyz123    9876    9875", False),
    ("1 xyz123    9876    9876\0", False),
    ]
for data, expected in tests:
    actual = bool(match_logon(data))
    print actual == expected, actual, expected, repr(data)

Results:
True True True '1 xyz123    9876    9876'
True True True ' xyz123    9876    9876'
True False False '0 xyz123    9876    9876'
False True False '5 xyz123    9876    9876'
True False False '1 xy1234    9876    9876'
True False False '5 xyz123    9876    9875'
True False False '1 xyz123    9876    9876\x00'
John Machin