Не удалось найти шаблон в строке с помощью регулярного выражения

#python #css #regex #string #hex

Вопрос:

Я пытаюсь извлечь все допустимые шестнадцатеричные значения, которые представляют цвет в CSS коде.

Технические характеристики шестнадцатеричного цветового кода

  1. Оно должно начинаться с символа»#».
  2. Он может содержать 3 или 6 цифр.
  3. Каждая цифра находится в диапазоне 0-F или 0-f.

Вот пример ввода

 #BED
{
    color: #FfFdF8; background-color:#aef;
    font-size: 123px;
    background: -webkit-linear-gradient(top, #f9f9f9, #fff);
}
#Cab
{
    background-color: #ABC;
    border: 2px dashed #fff;
}
 

Пример вывода

 #FfFdF8
#aef
#f9f9f9
#fff
#ABC
#fff
 

Объяснение

#КРОВАТЬ и #Кабина удовлетворяют критериям шестнадцатеричного цветового кода, но они используются в качестве селекторов, а не в качестве цветовых кодов в данном CSS. Таким образом, фактические цветовые коды являются

 #FfFdF8
#aef
#f9f9f9
#fff
#ABC
#fff
 

Что я пробовал в python

 import re
pattern = r'^#([A-Fa-f0-9]{3}){1,2}

Когда я запускаю приведенный выше код на примере ввода, он ничего не печатает.
Так что же плохого я здесь делаю? Это совпадающий шаблон? Или это та логика, которую я применяю?

Пожалуйста, кто-нибудь, объясните мне!


Комментарии:

1. Ваш шаблон закреплен с ^ помощью и $ . Таким образом, он будет совпадать только в том случае, если вся строка представляет собой одно шестнадцатеричное число, оно не будет совпадать в середине строки.

2. Спасибо @Barmar, я изменил шаблон на r'(#([A-Fa-f0-9]{3}){1,2})' , теперь он соответствует #FfFdF8 , но также dF8 . Теперь, что я должен сделать, чтобы он соответствовал только #FfFdF8 ?

3. Я не понимаю, как это может совпадать df8 , когда это не начинается с # самого начала .

4. Избавьтесь от групп захвата, вам это не нужно findall() . Это возвращает группы вместо всего матча.

5. Итак, что я должен использовать вместо findall() этого, чтобы получить желаемый результат?

Ответ №1:

Избавьтесь от якорей ^ и $ , поскольку они делают его соответствующим только всей входной строке.

Избавьтесь от групп захвата, чтобы re.findall() возвращались только целые совпадения, а не групповые совпадения. Используйте (?:...) для создания группы без захвата, чтобы вы могли использовать {1,2} квантификатор.

 pattern = r'#(?:[A-Fa-f0-9]{3}){1,2}'
 

Ответ №2:

У вас проблема из двух или трех частей:

  1. Удалите комментарии CSS, которые часто содержат материалы, похожие на код (необязательно, но рекомендуется).
    • Комментарии, соответствующие регулярному выражению, являются /*.*?*/
  2. Смотрите только внутрь фигурных скобок (например, не на селекторы).
    • Регулярное выражение, соответствующее фигурным скобкам, является {.*?}
  3. найдите цветовые коды
    • Регулярное выражение для цветовых кодов является #(?:[A-Fa-f0-9]{3}){1,2}

Сводя все это воедино:

 import re
def color_codes(css_text):
    codes = []
    # remove comments
    css_text = re.sub(r'/*.*?*/', '', css_text, re.S)
    # consider only {} blocks
    for block in re.finditer(r'{.*?}', css_text, re.S):
        # find color codes
        codes.extend(re.findall(r'#(?:[A-Fa-f0-9]{3}){1,2}', block.group(0)))
    return codes
 

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

n = int(input())
hexNum = []
for _ in range(n):
s = input()
if ':' in s and '#' in s:
result = re.findall(pattern,s)
if result:
hexNum.extend(result)
for num in hexNum:
print(num)
Когда я запускаю приведенный выше код на примере ввода, он ничего не печатает.
Так что же плохого я здесь делаю? Это совпадающий шаблон? Или это та логика, которую я применяю?

Пожалуйста, кто-нибудь, объясните мне!

Комментарии:

1. Ваш шаблон закреплен с ^ помощью и $ . Таким образом, он будет совпадать только в том случае, если вся строка представляет собой одно шестнадцатеричное число, оно не будет совпадать в середине строки.

2. Спасибо @Barmar, я изменил шаблон на r'(#([A-Fa-f0-9]{3}){1,2})' , теперь он соответствует #FfFdF8 , но также dF8 . Теперь, что я должен сделать, чтобы он соответствовал только #FfFdF8 ?

3. Я не понимаю, как это может совпадать df8 , когда это не начинается с # самого начала .

4. Избавьтесь от групп захвата, вам это не нужно findall() . Это возвращает группы вместо всего матча.

5. Итак, что я должен использовать вместо findall() этого, чтобы получить желаемый результат?

Ответ №1:

Избавьтесь от якорей ^ и $ , поскольку они делают его соответствующим только всей входной строке.

Избавьтесь от групп захвата, чтобы re.findall() возвращались только целые совпадения, а не групповые совпадения. Используйте (?:...) для создания группы без захвата, чтобы вы могли использовать {1,2} квантификатор.


Ответ №2:

У вас проблема из двух или трех частей:

  1. Удалите комментарии CSS, которые часто содержат материалы, похожие на код (необязательно, но рекомендуется).
    • Комментарии, соответствующие регулярному выражению, являются /*.*?*/
  2. Смотрите только внутрь фигурных скобок (например, не на селекторы).
    • Регулярное выражение, соответствующее фигурным скобкам, является {.*?}
  3. найдите цветовые коды
    • Регулярное выражение для цветовых кодов является #(?:[A-Fa-f0-9]{3}){1,2}

Сводя все это воедино:


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