Регулярне вираження, щоб перевірити, чи є пароль "8 символів, включаючи 1 велику літеру, 1 спеціальний символ, буквено-цифрові символи"


102

Я хочу регулярний вираз, щоб перевірити це

пароль повинен містити вісім символів, включаючи одну велику літеру, один спеціальний символ та буквено-цифрові символи.

І ось мій вираз перевірки, який складається з восьми символів, включаючи одну велику літеру, одну малу літеру та одне число або спеціальний символ.

(?=^.{8,}$)((?=.*\d)|(?=.*\W+))(?![.\n])(?=.*[A-Z])(?=.*[a-z]).*$"

Як я можу написати його для пароля, який повинен містити вісім символів, включаючи одну велику літеру, один спеціальний символ та буквено-цифрові символи?


26
Чому для цього вам потрібен регулярний вираз? Повний регулярний вираз, що відповідає вашим вимогам, буде дуже довгим і складним. Простіше написати свої обмеження в C # коді.
Грег Х'югілл

32
Ви розглядали можливість перевірки надійного пароля, а не перевірки відповідності паролю деяким довільним правилам, які є недосконалим проксі-сервером для надійного пароля? Існує безліч бібліотек і програм, які при введенні пароля визначатимуть його силу.
Уейн Конрад

4
@GregHewgill Я б схвалив ваш коментар, якби міг :-) Це виглядає як черговий випадок "якщо все, що у вас є, молоток, все починає виглядати як цвях".
Крістіан.К

3
Вам потрібен саме один великий / спеціальний символ або хоча б один?
mmdemirbas

4
За вимогою користувача, чи маєте ви на увазі, що ваш користувач диктує деталі реалізації? Можливо, тоді вони повинні просто це кодувати. Якщо чесно, я думаю, що було б легше підтримувати і розуміти, якби ви просто створили лічильники і перевіряли кожен символ один за одним, збільшуючи відповідні лічильники для кожного символу, який відповідає правилу. З технічної точки зору, це не те, що когось вразить, але навіщо ускладнювати речі тим, що буде схильним до помилок і важко оновити?

Відповіді:


132

Регулярний вираз, за ​​яким ви хочете, буде, швидше за все, величезним і кошмаром для підтримки, особливо для людей, які не такі знайомі з регулярними виразами.

Я думаю, що було б легше зруйнувати свій регекс і робити це по черзі. Це може зайняти трохи більше, але я впевнений, що зберегти його та налагодити це буде простіше. Це також дозволить надавати вашим користувачам більш спрямовані повідомлення про помилки (крім простого Invalid Password), що повинно покращити роботу користувачів.

З того, що я бачу, ти досить добре володієш регулярними виразами, тому я б припустив, що давати тобі регулярні вислови робити те, що потрібно, буде марним.

Бачачи ваш коментар, ось як я б це зробив:

  • Повинно бути вісім символів Довго: для цього вам не потрібен регулярний вираз. Використання .Lengthвластивості має бути достатньо.

  • Включаючи одну велику літеру: Ви можете використовувати [A-Z]+регулярний вираз. Якщо рядок містить принаймні одну верхню літеру, це регулярне вираження дасть результат true.

  • Один спеціальний символ: Ви можете використовувати або той, \Wякий буде відповідати будь-якому символу, який не є літерою чи цифрою, або ви можете використовувати щось подібне, [!@#]щоб вказати спеціальний список спеціальних символів. Зверніть увагу , однак , що такі символи, як $, ^, (і )спеціальні символи в мові регулярних виразів, тому вони повинні бути екрановані , як так: \$. Отже, коротше, ви можете використовувати \W.

  • Буквено-цифрові символи: Використання знака \w+має відповідати будь-якій літери та цифрі та підкресленню.

Перегляньте цей підручник для отримання додаткової інформації.


2
я не писав цього свого, я отримую його від дорогого друга Google,
Ранія Умайр,

4
@RaniaUmair: Я думаю, що ваш коментар підтверджує мою думку. Я рекомендую вам розбити його так, як я вказав.
npinti

35
+1 Regex є потужним, але не мав на меті вирішити жодну проблему у Всесвіті
Крістіан Лупаску,

@ w0lf: Я більше не могла погодитися. Regex є потужним, проте він стає занадто складним занадто швидко, тому краще тримати його просто.
npinti

Ви можете мені допомогти мені потрібен регрес, який може приймати принаймні одне число і максимум 3 інші charecters може бути будь-що
Lijo

107
(                   # Start of group
    (?=.*\d)        #   must contain at least one digit
    (?=.*[A-Z])     #   must contain at least one uppercase character
    (?=.*\W)        #   must contain at least one special symbol
       .            #     match anything with previous condition checking
         {8,8}      #        length is exactly 8 characters
)                   # End of group

В одному рядку:

((?=.*\d)(?=.*[A-Z])(?=.*\W).{8,8})

Редагувати 2019-05-28:

Вам потрібно узгодити весь вхідний рядок. Отже, ви можете вкласти регекс між ^і $запобігти випадковому прийняттю часткових збігів як відповідності всього вводу:

^((?=.*\d)(?=.*[A-Z])(?=.*\W).{8,8})$

Джерела:


58
Тому що він складається з 12 символів
mmdemirbas

ще одна умова не повинна починатися з цифри, як я можу це зробити?
Лійо

7
Ви можете скоротити його, використовуючи {8}, щоб відповідати 8 символам
Анджело Трикаріко

його відповідність для $ 1eerrrrrrr .. у неї немає великої літери.
Шилпі

@ShilpiJaiswal Або ви використовуєте прапор для невідчутливого до регістру матчу, або робите "знаходження" замість "матчу". Щоб переконатися, що ви узгоджуєте весь вхідний рядок, ви можете вкласти регулярний вираз між ^і $. Спробуйте це:^((?=.*\d)(?=.*[A-Z])(?=.*\W).{8,8})$
mmdemirbas

35

Стільки відповідей .... все погано!

У регулярних виразах немає оператора AND, тому досить складно написати регулярний вираз, який відповідає дійсним паролям, коли дійсність визначається чимось І чимось І ЧИМИ ...

Але регулярні вирази дійсно є оператор АБО, так просто застосувати теорему де Моргана, і написати регулярний вираз , яке відповідає недійсні паролів.

все, що має менше 8 символів АБО що- небудь, без цифр АБО, що не має великих літер, АБО нічого, що не має спеціальних символів

Так:

^(.{0,7}|[^0-9]*|[^A-Z]*|[a-zA-Z0-9]*)$

Якщо щось відповідає цьому, то це недійсний пароль.


3
Якщо OP хотів рівно 8 символів, то вам потрібно буде додати |.{9,}. +1 для концепції
Даніель

Чудове і просте рішення питання, хоча я згоден, що єдиний регулярний вираз не є оптимальним для реальної проблеми.
Siderite Zackwehdex

1
Регулярні вирази дійсно є і оператори, вони називаються LOOKAHEAD / Твердження щодо попереднього тексту.
порівняно_випадково

13

Відповідь - не використовувати регулярний вираз. Це множини і підрахунок.

Регулярні вирази стосуються порядку.

У своєму житті як програміста вас попросять зробити багато речей, які не мають сенсу. Навчіться копати рівень глибше. Дізнайтеся, коли питання неправильне.

Питання (якщо воно згадувало регулярні вирази) є помилковим.

Псевдокод (перемикання між занадто великою кількістю мов, пізніх):

if s.length < 8:
    return False
nUpper = nLower = nAlphanum = nSpecial = 0
for c in s:
    if isUpper(c):
        nUpper++
    if isLower(c):
        nLower++
    if isAlphanumeric(c):
        nAlphanum++
    if isSpecial(c):
        nSpecial++
return (0 < nUpper) and (0 < nAlphanum) and (0 < nSpecial)

Ставка, що ви прочитали та зрозуміли вищевказаний код майже миттєво. Зрозуміло, що ви взяли набагато більше часу з регулярним виразом, і менш впевнені, що це правильно. Розширення регулярного вираження ризиковано. Розширений безпосередньо вище, набагато менше.

Зверніть увагу також на те, що питання є чітко викладеним. Чи набір символів ASCII або Unicode, або ?? Моя здогадка, читаючи питання, полягає в тому, що принаймні один малий символ передбачається. Тому я вважаю, що останнім правилом повинно бути:

return (0 < nUpper) and (0 < nLower) and (0 < nAlphanum) and (0 < nSpecial)

(Зміна капелюхів на орієнтовану на безпеку, це дійсно дратує / не корисне правило.)

Навчитися знати, коли питання неправильне, важливіше, ніж розумні відповіді. Розумна відповідь на неправильне питання майже завжди неправильна.


2
Я згоден. Чим більше людей, з якими ви працюєте, тим більше код повинен бути читабельний, хоча деяка реалізація
повторних

Мені подобається, що деякі користувачі, як ти, мають сміливість сказати, що Regex - це не завжди краще рішення, яке застосовується, і коли-небудь просте програмування є більш читабельним.
schlebe

12

Як приклад, як це можна зробити за допомогою читабельного / ремонтованого регулярного вираження.

Для більш тривалого регулярного вираження ви завжди повинні використовувати RegexOptions.IgnorePatternWhitespaceпробіли та коментарі у виразі для кращої читабельності.

String[] passwords = { "foobar", "Foobar", "Foobar1", "Fooobar12" };

foreach (String s in passwords) {

    Match password = Regex.Match(s, @"
                                      ^              # Match the start of the string
                                       (?=.*\p{Lu})  # Positive lookahead assertion, is true when there is an uppercase letter
                                       (?=.*\P{L})   # Positive lookahead assertion, is true when there is a non-letter
                                       \S{8,}        # At least 8 non whitespace characters
                                      $              # Match the end of the string
                                     ", RegexOptions.IgnorePatternWhitespace);

    if (password.Success) {
        Console.WriteLine(s + ": valid");
    }
    else {
        Console.WriteLine(s + ": invalid");
    }
}

Console.ReadLine();

Це найкращий спосіб зловживати lookahead assertionяк своєрідним «і» шаблоном, щоб охопити все обмеження в межах одного регулярного вираження. Працює для більшої кількості обмежень і їх можна легко генерувати, якщо деякі обмеження повинні бути включені / відключені конфігурацією.
прогнозуйте

2
Використання категорій Unicode - відмінна ідея. Світ ширший за ASCII!
Вальтер Трос

1

Якщо вам потрібен лише один верхній регістр та спеціальний символ, то це має працювати:

@"^(?=.{8,}$)(?=[^A-Z]*[A-Z][^A-Z]*$)\w*\W\w*$"

AAaaaaaaa#Відповідно до цього виразу, рядок не в порядку
Крістіан Лупаску,

3
Ну, це 10, а не 8 символів і містить більше одного останнього верхнього регістру, тому він повинен вийти з ладу ...
user1096188

4
Ви праві, це говорить про це у запитанні. Я вважав, що ці правила більше схожі на "принаймні одну велику літеру", а не "рівно одну велику" . Я не впевнений, що саме цього хотіла ОП.
Крістіан Лупаску,


0

Це питання починає бути вірусним і з’явилося багато цікавих пропозицій.

Так, писати від руки важко. Тож простішим рішенням є використання шаблону. Хоча отриманий регулярний вираз може бути не найбільш оптимальним, його буде легше підтримувати та / або змінювати, а користувач матиме кращий контроль над результатом. Цілком можливо, що я щось пропустив, тому будь-яка конструктивна критика буде корисною.

Ці посилання можуть бути цікавими: зіставте принаймні дві цифри по 2 літери в будь-якому порядку в рядку , мова регулярного вираження , групи захоплення

Я використовую цей шаблон (?=(?:.*?({type})){({count})})на основі всього регексу, який я бачив у програмі SO. Наступний крок - заміна необхідного шаблону ( number, special character...) та додавання конфігурації по довжині.

Я створив невеликий клас для складання регулярного виразу PasswordRegexGenerator.cs Приклад:

string result = new PasswordRegexGenerator ( )
        .UpperCase ( 3, -1 )    // ... {3,}
        .Number ( 2, 4 )        // ... {2,4}
        .SpecialCharacter ( 2 ) // ... {2}
        .Total ( 8,-1 )
        .Compose ( );

/// <summary>
/// Generator for regular expression, validating password requirements.
/// </summary>
public class PasswordRegexGenerator
{
    private string _elementTemplate = "(?=(?:.*?({type})){({count})})";

    private Dictionary<string, string> _elements = new Dictionary<string, string> {
        { "uppercase", "[A-Z]" },
        { "lowercase", "[a-z]" },
        { "number", @"\d" },
        { "special", @"\W" },
        { "alphanumeric", @"\w" }
    };

    private StringBuilder _sb = new StringBuilder ( );

    private string Construct ( string what, int min, int max )
    {
        StringBuilder sb = new StringBuilder ( _elementTemplate );
        string count = min.ToString ( );

        if ( max == -1 )
        {
            count += ",";
        }
        else if ( max > 0 )
        {
            count += "," + max.ToString();
        }

        return sb
            .Replace ( "({type})", what )
            .Replace ( "({count})", count )
            .ToString ( );
    }

    /// <summary>
    /// Change the template for the generation of the regex parts
    /// </summary>
    /// <param name="newTemplate">the new template</param>
    /// <returns></returns>
    public PasswordRegexGenerator ChangeRegexTemplate ( string newTemplate )
    {
        _elementTemplate = newTemplate;
        return this;
       }

    /// <summary>
    /// Change or update the regex for a certain type ( number, uppercase ... )
    /// </summary>
    /// <param name="name">type of the regex</param>
    /// <param name="regex">new value for the regex</param>
    /// <returns></returns>
    public PasswordRegexGenerator ChangeRegexElements ( string name, string regex )
    {
        if ( _elements.ContainsKey ( name ) )
        {
            _elements[ name ] = regex;
        }
        else
        {
            _elements.Add ( name, regex );
        }
        return this;
    }

    #region construction methods 

    /// <summary>
    /// Adding number requirement
    /// </summary>
    /// <param name="min"></param>
    /// <param name="max"></param>
    /// <returns></returns>
    public PasswordRegexGenerator Number ( int min = 1, int max = 0 )
    {
        _sb.Append ( Construct ( _elements[ "number" ], min, max ) );
        return this;
    }

    public PasswordRegexGenerator UpperCase ( int min = 1, int max = 0 )
    {
        _sb.Append ( Construct ( _elements[ "uppercase" ], min, max ) );
        return this;
    }

    public PasswordRegexGenerator LowerCase ( int min = 1, int max = 0 )
    {
        _sb.Append ( Construct ( _elements[ "lowercase" ], min, max ) );
        return this;
    }

    public PasswordRegexGenerator SpecialCharacter ( int min = 1, int max = 0 )
    {
        _sb.Append ( Construct ( _elements[ "special" ], min, max ) );
        return this;
    }

    public PasswordRegexGenerator Total ( int min, int max = 0 )
    {
        string count = min.ToString ( ) + ( ( max == 0 ) ? "" : "," + max.ToString ( ) );
        _sb.Append ( ".{" + count + "}" );
        return this;
    }

    #endregion

    public string Compose ()
    {
        return "(" + _sb.ToString ( ) + ")";
    }
}

0

Ви можете використовувати нижче клас для перевірки:

public class PasswordValidator{

  private Pattern pattern;
  private Matcher matcher;

  private static final String PASSWORD_PATTERN =
          "((?=.*\\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%]).{6,20})";

  public PasswordValidator(){
      pattern = Pattern.compile(PASSWORD_PATTERN);
  }

  /**
   * Validate password with regular expression
   * @param password password for validation
   * @return true valid password, false invalid password
   */
  public boolean validate(final String password){

      matcher = pattern.matcher(password);
      return matcher.matches();

  }
}

де 6 і 20 - мінімальна і максимальна довжина пароля.


0
  • Використовуйте вираз без зворотного відстеження, щоб спочатку зрівняти весь пароль, якщо він містить щонайменше 8 символів (таким чином, комбінаторний вибух довгих, але недійсних паролів немає): (?>{8,})
  • Скористайтеся твердженнями, що знаходяться позаду, щоб перевірити наявність усіх необхідних символів (AND-умов). (?<=...)
  • Принаймні один верхній регістр: (?<=\p{Lu}.*)
  • Принаймні один спеціальний символ (трохи неоднозначний, але давайте використовувати не слово): (?<=\W.*)
  • Принаймні один буквено-цифровий символ (: (?<=\w.*)

Підведені:

(?>.{8,})(?<=\p{Lu}.*)(?<=\W.*)(?<=\w.*)


0

Найкраще - використовувати не регулярно. Ці вимоги дуже легкі. На процесорних рядкових операціях перевірка критеріїв / перевірки набагато дешевше і швидше, ніж у регулярному вираженні!


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

15
Я пропоную вам відредагувати своє запитання та включити пояснення. Відповіді, що стосуються лише коду, іноді досить хороші, але відповіді з кодом + поясненням завжди кращі
Barranka
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.