Шаблон 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