Шаблон Regex, позволяющий использовать буквенно-цифровые и квадратные скобки с текстом внутри

Я использую regex для разрешения буквенно-цифровых символов, подчеркивания, дефиса и квадратных скобок в текстовом поле. regex, который я использую для проверки ввода, имеет вид

  r'^[a-zA-Z0-9_\-\[\] ]*$.

Мне нужно изменить регекс таким образом, чтобы при наличии пустых скобок он возвращал false.

Выборочные случаи

"Ваше сообщение здесь" - Действительное

"Ваше [текстовое] сообщение здесь" - Действительное

"ваш_текст_сообщения [текст]" - valid

"Ваше [] сообщение здесь" - Недействительно

"[] сообщение" - Недействительно

Может ли это быть так?

^(?!.*\[\s*\].*)[a-zA-Z0-9_\-\[\] ]*$

В приведенных примерах должна работать следующая схема, хотя может существовать и более лаконичная версия:

^[a-zA-Z0-9_\- ]*(?:\[[a-zA-Z0-9_\- ]+\])?[a-zA-Z0-9_\- ]*$

Вкратце:

  • Мы не включаем квадратные скобки в наше начальное соответствие
  • Мы используем необязательную группу не захвата, чтобы убедиться, что все, что находится между квадратными скобками, соответствует правильному шаблону
  • .
  • Затем мы повторяем это начальное соответствие в конце.

Попробуйте использовать это выражение:

import re

lst = ["Your message here", "Your [text] message here", '[] jrejnei', 'ggyy [] uhihihu']
pattern = re.compile(r'^(?!.*\[\s*\])[a-zA-Z0-9_\-\[\] ]*$')

for i in lst:
    if pattern.search(i):
        print(i)

Вывод:

Your message here
Your [text] message here

Объяснение: Regex 101

Это можно решить с помощью группировки и повторений с использованием шаблона ^(([\w\- ])+(\[[\w\- ]+\])*)+$. Я упростил задачу, используя \w, который будет соответствовать любому символу <слову, то есть алфавитно-цифровым символам плюс подчеркиванию. Шаблон соответствует любому из \w, - или , повторенному хотя бы один раз, за которым следует любое количество необязательных секций, заключенных в скобки (содержащих тот же шаблон). Весь шаблон должен быть повторен хотя бы один раз (таким образом, пустая строка исключается).

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

Код ниже

import re

pat = re.compile(r'^(([\w\- ])+(\[[\w\- ]+\])*)+$')

for x in ["Your message here", "Your [text] message here", "your_text_message [text]", "Your [] message here", "[] message"]:
     if re.search(pat, x):
         print(f"{x} - Valid")
     else:
         print(f"{x} - Invalid")

печатает

Your message here - Valid
Your [text] message here - Valid
your_text_message [text] - Valid
Your [] message here - Invalid
[] message - Invalid

Добавление некоторых поведений, которые могут показаться вам интересными:

  • Примите более одного блока скобок :
    ✔️ [user] lives in [city]

  • Как вы упомянули в комментарии, ограничьте длину слова внутри блока скобок :
    ✔️ [text] принято
    ❌ но не [something_too_long_for_you]

  • Убедитесь, что слово в блоке скобок является переменной :
    ✔️ [super_man_1] принято
    ❌ но не [21_pilots] ни [week-end], ни [?shit!]

  • Допускаются необязательные пробелы в блоке скобок :
    ✔️ [ text ]

  • Прием подчеркиваний с поддержкой Юникода :
    ✔️ Cañon City: [text]

  • Примите пунктуацию :
    ✔️ [user], it's fine, no?

  • Не принимать блоки с незакрытыми скобками :
    Hey [ this is not valid

Для регулярного выражения я использовал следующие флаги :

  • Ex расширенная нотация regex (называемая verbose в Python), чтобы добавить добавить несколько комментариев, чтобы сделать его читабельным.

  • Флаг чувствительности к регистру i для записи [a-z] вместо [a-zA-Z].

  • u флаг никода, чтобы \w также соответствовал подчеркнутым буквам.

Шаблон regex, на Python :

import re

regex_pattern = r"""
    ^
    # A block, 0 or several times, with 2 alternatives:
    (?:
      # A valid char: letter, space or a simple punctuation char.
      [\w \-.,:;!?'\"]
    |
      # Brackets with a var of max 15 chars, with optional spaces around:
      \[\s*                # Opening bracket and optional spaces.
      [a-z][a-z_0-9]{,14}  # A valid variable name.
      \s*\]                # Optional spaces and closing bracket.
    )*
    $
    """

regex = re.compile(regex_pattern, re.VERBOSE | re.UNICODE | re.IGNORECASE)

tests = [
    "Your [text] message here",
    "[username] wrote [text]",
    "your_text_message [text]",
    "With optional spaces in around the word [ text ] [ user_id]",
    "A message without brackets, but with \"valid\" punctuation.",
    "Accents allowed with unicode support, it's Okây?",
    "Your [] message here",
    "[] message",
    "Missing text between brackets [   ]",
    "To much stuff between brackets [A23456789B123456]",
    "Again word more than 15 chars [ this_one_is_long ]",
    "Invalid var name: [not-valid-var]",
    "Invalid var name: [2do]",
    "Invalid var name: [user.name], could be accepted if you change the rule."
]

for test in tests:

    print(test)

    if regex.match(test):
        print("OK\n")
    else:
        print("NOT OK\n")

Протестируйте и поиграйте с regex здесь: https://regex101.com/r/zE73Wu/1

Или запустите полный Python код здесь: https://onecompiler.com/python/42fx3xgd6

Вернуться на верх