Задача на проверку формата строки regex

При решении следующей задачи: На вход в программу поступает цвет CSS RGB(A), необходимо определить действителен ли его формат. Создайте функцию, которая принимает строку (например, «rgb (0, 0, 0)») и возвращает True, если формат правильный, в противном случае возвращает False. Данные могут поступать как в формате rgb, так и rgba.

Допустимые значения: rgb(0-255, 0-255, 0-255), rgb(0-100%, 0-100%, 0-100%), rgba(0-255, 0-255, 0-255, 0-1)
Возможные форматы ввода:

rgb(0%,50%,100%) ---> True  
rgba(0,0,0,0)    ---> True  
rgb(255,255,255) ---> True  
rgb(0,,0)        ---> False  
rgb(-1,0,0)      ---> False  
rgba(0,0,0,1.5)  ---> False  
rgba(0,0,0,0.5)  ---> True

rgb(-1,0,0)      ---> False

столкнулся с рядом проблем, а именно:

  1. Как установить интервалы для цифровых значений в скобках? В данный момент код не ограничивает значения до 255;
  2. Как ограничить длину строки? В данный момент, если ввести корректный формат rgb(255,255,255)rgb(255,255,255), то выдаст True.
  3. Как можно объединить 2 заключительных паттерна, чтобы можно было указывать значения с плавающей точкой 4 аргумента в rgba?

Мой код:


    import re
    
    x = input()
    my_patterns_check = [re.search(r'(?:rgb\()(?:\d{1,3})(?:,\d{1,3}){2}\)$', x),
                         re.search(r'(?:rgb\()(?:\d{1,3}\%)(?:,\d{1,3}\%){2}\)$', x),
                         re.search(r'(?:rgba\()(?:\d{1,3})(?:,\d{1,3}){2}(?:,\d{1}\))$', x),
                         re.search(r'(?:rgba\()(?:\d{1,3})(?:,\d{1,3}){2}(?:,\d{1}\.\d{1}\))$', x)
                        ]
    if any(my_patterns_check):
        print(True)
    else:
        print(False)

Спасибо за ваши комментарии!


Ответы (1 шт):

Автор решения: Wiktor Stribiżew

Сначала просто объединим 3 и 4 шаблоны в (?:rgba\()(?:\d{1,3})(?:,\d{1,3}){2}(?:,\d{1}(?:\.\d{1})?\))$, так будет меньше работы. Квантификатор {1} вообще никогда не нужен, его надо удалять всегда.

Чтобы проверять целую строку на совпадение, используйте re.fullmatch, а не re.search. Тогда и $ не нужен.

Выражение для поиска чисел от 0 до 100 — (?:\d{1,2}(?:\.\d+)?|100(?:\.0+)?), от нуля до 255 — (?:1?[0-9]{1,2}|2[0-4][0-9]|25[0-5]), от 0 до 1 — (?:0(?:\.\d+)?|1(?:\.0+)?).

Используйте

my_patterns_check = [
    re.fullmatch(r'rgb\((?:1?[0-9]{1,2}|2[0-4][0-9]|25[0-5])(?:,(?:1?[0-9]{1,2}|2[0-4][0-9]|25[0-5])){2}\)', x),
    re.fullmatch(r'rgb\((?:\d{1,2}(?:\.\d+)?|100(?:\.0+)?)%(?:,(?:\d{1,2}(?:\.\d+)?|100(?:\.0+)?)%){2}\)', x),
    re.fullmatch(r'rgba\((?:1?[0-9]{1,2}|2[0-4][0-9]|25[0-5])(?:,(?:1?[0-9]{1,2}|2[0-4][0-9]|25[0-5])){2},(?:0(?:\.\d+)?|1(?:\.0+)?)\)', x),
]
→ Ссылка