Объяснение Lookaheads в этом регулярном выражении - PullRequest
7 голосов
/ 07 августа 2009

Я достаточно хорошо понимаю регулярные выражения, но не могу использовать их достаточно часто, чтобы быть экспертом. Я наткнулся на регулярное выражение, которое я использую для проверки надежности пароля, но оно содержит некоторые понятия регулярных выражений, с которыми я не знаком. Регулярное выражение:

^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{6,}$

и простым языком это означает, что строка должна содержать как минимум один символ нижнего регистра, один символ верхнего регистра и одно число, а длина строки должна быть не менее шести символов. Может ли кто-нибудь объяснить это, чтобы я объяснил, как этот шаблон на самом деле описывает это правило? Я вижу начало строки char ^ и конец строки char $, три группы с заглядыванием, совпадение с любым символом. и повторение {6,}.

Спасибо любому гуру регулярных выражений, который может помочь мне разобраться с этим.

Ответы [ 5 ]

14 голосов
/ 07 августа 2009

В обычных условиях фрагмент регулярного выражения соответствует фрагменту входной строки и «потребляет» этот фрагмент строки. Следующий фрагмент выражения соответствует следующему фрагменту строки и т. Д.

утверждения Lookahead не не потребляют ни одной строки, поэтому ваши три утверждения Lookahead:

  • (?=.*\d)
  • (?=.*[a-z])
  • (?=.*[A-Z])

каждый означает «Этот шаблон (все, что следует за цифрой, строчной буквой, заглавной буквой соответственно) должен появляться где-то в строке», но они не перемещают текущую позицию соответствия вперед, поэтому остаток выражение:

  • .{6,}

(что означает «шесть или более символов») должно по-прежнему соответствовать всей входной строке.

5 голосов
/ 07 августа 2009

Предварительная группа не использует ввод. Таким образом, одни и те же символы на самом деле сопоставляются разными группами просмотра.

Вы можете думать об этом так: ищите что-нибудь (.*), пока не найдете цифру (\d). Если вы это сделаете, вернитесь к началу этой группы (концепция предвидения). Теперь ищите что-нибудь (.*), пока не найдете строчную букву. Повторите для заглавной буквы. Теперь сопоставьте любые 6 или более символов.

4 голосов
/ 07 августа 2009

Чтобы сломать его полностью.

^ -- Match beginning of line
(?=.*\d) -- The following string contains a number
(?=.*[a-z]) -- The following string contains a lowercase letter
(?=.*[A-Z]) -- The following string contains an uppercase letter
.{6,} -- Match at least 6, as many as desired of any character
$ -- Match end of line
1 голос
/ 07 августа 2009

Я пошел и проверил, как это будет соответствовать, если использовать Perl:

perl -Mre=debug -E'q[  abc  345 DEF  ]=~/^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{6,}$/'

Compiling REx "^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{6,}$"
synthetic stclass "ANYOF[\0-\11\13-\377{unicode_all}]".
Final program:
   1: BOL (2)
   2: IFMATCH[0] (9)
   4:   STAR (6)
   5:     REG_ANY (0)
   6:   DIGIT (7)
   7:   SUCCEED (0)
   8: TAIL (9)
   9: IFMATCH[0] (26)
  11:   STAR (13)
  12:     REG_ANY (0)
  13:   ANYOF[a-z] (24)
  24:   SUCCEED (0)
  25: TAIL (26)
  26: IFMATCH[0] (43)
  28:   STAR (30)
  29:     REG_ANY (0)
  30:   ANYOF[A-Z] (41)
  41:   SUCCEED (0)
  42: TAIL (43)
  43: CURLY {6,32767} (46)
  45:   REG_ANY (0)
  46: EOL (47)
  47: END (0)

floating ""$ at 6..2147483647 (checking floating) stclass ANYOF[\0-\11\13-\377{unicode_all}] anchored(BOL) minlen 6 
Guessing start of match in sv for REx "^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{6,}$" against "  abc  345 DEF  "
Found floating substr ""$ at offset 16...
start_shift: 6 check_at: 16 s: 0 endpos: 11
Does not contradict STCLASS...
Guessed: match at offset 0
Matching REx "^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{6,}$" against "  abc  345 DEF  "
   0 <> <  abc  345>         |  1:BOL(2)
   0 <> <  abc  345>         |  2:IFMATCH[0](9)
   0 <> <  abc  345>         |  4:  STAR(6)
                                    REG_ANY can match 16 times out of 2147483647...
  16 <c  345 DEF  > <>       |  6:    DIGIT(7) # failed...
  15 <c  345 DEF > < >       |  6:    DIGIT(7) # failed...
  14 <c  345 DEF> <  >       |  6:    DIGIT(7) # failed...
  13 <c  345 DE> <F  >       |  6:    DIGIT(7) # failed...
  12 <c  345 D> <EF  >       |  6:    DIGIT(7) # failed...
  11 <c  345 > <DEF  >       |  6:    DIGIT(7) # failed...
  10 <c  345> < DEF  >       |  6:    DIGIT(7) # failed...
   9 <c  34> <5 DEF  >       |  6:    DIGIT(7)
  10 <c  345> < DEF  >       |  7:    SUCCEED(0)
                                      subpattern success...
   0 <> <  abc  345>         |  9:IFMATCH[0](26)
   0 <> <  abc  345>         | 11:  STAR(13)
                                    REG_ANY can match 16 times out of 2147483647...
  16 <c  345 DEF  > <>       | 13:    ANYOF[a-z](24) # failed...
  15 <c  345 DEF > < >       | 13:    ANYOF[a-z](24) # failed...
  14 <c  345 DEF> <  >       | 13:    ANYOF[a-z](24) # failed...
  13 <c  345 DE> <F  >       | 13:    ANYOF[a-z](24) # failed...
  12 <c  345 D> <EF  >       | 13:    ANYOF[a-z](24) # failed...
  11 <c  345 > <DEF  >       | 13:    ANYOF[a-z](24) # failed...
  10 <c  345> < DEF  >       | 13:    ANYOF[a-z](24) # failed...
   9 <c  34> <5 DEF  >       | 13:    ANYOF[a-z](24) # failed...
   8 <bc  3> <45 DEF  >      | 13:    ANYOF[a-z](24) # failed...
   7 <abc  > <345 DEF  >     | 13:    ANYOF[a-z](24) # failed...
   6 < abc > < 345 DEF  >    | 13:    ANYOF[a-z](24) # failed...
   5 <  abc> <  345 DEF >    | 13:    ANYOF[a-z](24) # failed...
   4 <  ab> <c  345 DEF>     | 13:    ANYOF[a-z](24)
   5 <  abc> <  345 DEF >    | 24:    SUCCEED(0)
                                      subpattern success...
   0 <> <  abc  345>         | 26:IFMATCH[0](43)
   0 <> <  abc  345>         | 28:  STAR(30)
                                    REG_ANY can match 16 times out of 2147483647...
  16 <c  345 DEF  > <>       | 30:    ANYOF[A-Z](41) # failed...
  15 <c  345 DEF > < >       | 30:    ANYOF[A-Z](41) # failed...
  14 <c  345 DEF> <  >       | 30:    ANYOF[A-Z](41) # failed...
  13 <c  345 DE> <F  >       | 30:    ANYOF[A-Z](41)
  14 <c  345 DEF> <  >       | 41:    SUCCEED(0)
                                      subpattern success...
   0 <> <  abc  345>         | 43:CURLY {6,32767}(46)
                                  REG_ANY can match 16 times out of 2147483647...
  16 <c  345 DEF  > <>       | 46:  EOL(47)
  16 <c  345 DEF  > <>       | 47:  END(0)
Match successful!
Freeing REx: "^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{6,}$"

Я немного изменил вывод

0 голосов
/ 07 августа 2009

Предварительные утверждения используются для того, чтобы в строке была хотя бы одна цифра, одна строчная и одна прописная буква.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...