Попытка удалить шестнадцатеричные коды из результатов регулярного выражения - PullRequest
5 голосов
/ 04 февраля 2010

Мой первый вопрос вот так!К точке;

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

[#.]([a-zA-Z0-9_\-])*

, который работает довольно хорошо и находит #TB_window, а также #TB_window img#TB_Image и .TB_Image#TB_window.

Проблема в том, что он также находит теги шестнадцатеричного кода вфайл CSS.то есть #FFF или #eaeaea.Также найдены .png или .jpg или и 0.75 ..

На самом деле, вполне логично, что они найдены, но разве нет разумных обходных путей для этого?Как исключить что-либо между скобками {..}?(Я почти уверен, что это возможно, но мой опыт регулярных выражений пока невелик).

Заранее спасибо!

Ура!Mike

Ответы [ 4 ]

2 голосов
/ 04 февраля 2010

CSS - это очень простой, обычный язык, который означает, что он может быть полностью проанализирован Regex.Все, что нужно сделать, - это группы селекторов, за которыми следует группа параметров, разделенных двоеточиями.

Обратите внимание, что все регулярные выражения в этом посте должны иметь подробный и dotall установлены флаги (/ s и / x в некоторых языках, re.DOTALL и re.VERBOSE в Python).

Чтобы получить пары (селекторы, правила):

\s*        # Match any initial space
([^{}]+?)  # Ungreedily match a string of characters that are not curly braces.
\s*        # Arbitrary spacing again.
\{         # Opening brace.
  \s*      # Arbitrary spacing again.
  (.*?)    # Ungreedily match anything any number of times.
  \s*      # Arbitrary spacing again.
\}         # Closing brace.

Это не будет работать в редком случае наличия заключенной в кавычки фигурной скобки в селекторе атрибута (например, img[src~='{abc}']) или в правиле (например, background: url('images/ab{c}.jpg')).Это можно исправить, усложнив регулярное выражение:

\s*        # Match any initial space
((?:       # Start the selectors capture group.
  [^{}\"\']           # Any character other than braces or quotes.
  |                   # OR
  \"                  # An opening double quote.
    (?:[^\"\\]|\\.)*  # Either a neither-quote-not-backslash, or an escaped character.
  \"                  # And a closing double quote.
  |                   # OR
  \'(?:[^\']|\\.)*\'  # Same as above, but for single quotes.
)+?)       # Ungreedily match all that once or more.
\s*        # Arbitrary spacing again.
\{         # Opening brace.
  \s*      # Arbitrary spacing again.
  ((?:[^{}\"\']|\"(?:[^\"\\]|\\.)*\"|\'(?:[^\'\\]|\\.)*\')*?)
           # The above line is the same as the one in the selector capture group.
  \s*      # Arbitrary spacing again.
\}         # Closing brace.
# This will even correctly identify escaped quotes.

Вау, это горстка.Но если вы подойдете к нему модульно, вы заметите, что он не так сложен, как кажется на первый взгляд.

Теперь, чтобы разделить селекторы и правила, мы должны сопоставить строки символов, которые либоне разделители (где разделитель - запятая для селекторов и точка с запятой для правил) или строки в кавычках с чем-либо внутри.Мы будем использовать тот же шаблон, который мы использовали выше.

Для селекторов:

\s*        # Match any initial space
((?:       # Start the selectors capture group.
  [^,\"\']             # Any character other than commas or quotes.
  |                    # OR
  \"                   # An opening double quote.
    (?:[^\"\\]|\\.)*   # Either a neither-quote-not-backslash, or an escaped character.
  \"                   # And a closing double quote.
  |                    # OR
  \'(?:[^\'\\]|\\.)*\' # Same as above, but for single quotes.
)+?)       # Ungreedily match all that.
\s*        # Arbitrary spacing.
(?:,|$)      # Followed by a comma or the end of a string.

Для правил:

\s*        # Match any initial space
((?:       # Start the selectors capture group.
  [^,\"\']             # Any character other than commas or quotes.
  |                    # OR
  \"                   # An opening double quote.
    (?:[^\"\\]|\\.)*   # Either a neither-quote-not-backslash, or an escaped character.
  \"                   # And a closing double quote.
  |                    # OR
  \'(?:[^\'\\]|\\.)*\' # Same as above, but for single quotes.
)+?)       # Ungreedily match all that.
\s*        # Arbitrary spacing.
(?:;|$)      # Followed by a semicolon or the end of a string.

Наконец, для каждого правила мы можем разделить(один раз!) на двоеточие для получения пары свойство-значение.

Объединение всего этого в программу Python (регулярные выражения такие же, как и выше, но не подробные для экономии места):

import re

CSS_FILENAME = 'C:/Users/Max/frame.css'

RE_BLOCK = re.compile(r'\s*((?:[^{}"\'\\]|\"(?:[^"\\]|\\.)*"|\'(?:[^\'\\]|\\.)*\')+?)\s*\{\s*((?:[^{}"\'\\]|"(?:[^"\\]|\\.)*"|\'(?:[^\'\\]|\\.)*\')*?)\s*\}', re.DOTALL)
RE_SELECTOR = re.compile(r'\s*((?:[^,"\'\\]|\"(?:[^"\\]|\\.)*\"|\'(?:[^\'\\]|\\.)*\')+?)\s*(?:,|$)', re.DOTALL)
RE_RULE = re.compile(r'\s*((?:[^;"\'\\]|\"(?:[^"\\]|\\.)*\"|\'(?:[^\'\\]|\\.)*\')+?)\s*(?:;|$)', re.DOTALL)

css = open(CSS_FILENAME).read()

print [(RE_SELECTOR.findall(i),
        [re.split('\s*:\s*', k, 1)
         for k in RE_RULE.findall(j)])
       for i, j in RE_BLOCK.findall(css)]

Для этого примера CSS:

body, p#abc, #cde, a img .fgh, * {
  font-size: normal; background-color: white !important;

  -webkit-box-shadow: none
}

#test[src~='{a\'bc}'], .tester {
  -webkit-transition: opacity 0.35s linear;
  background: white !important url("abc\"cd'{e}.jpg");
  border-radius: 20px;
  opacity: 0;
  -webkit-box-shadow: rgba(0, 0, 0, 0.6) 0px 0px 18px;
}

span {display: block;} .nothing{}

... мы получаем (с интервалом для ясности):

[(['body',
   'p#abc',
   '#cde',
   'a img .fgh',
   '*'],
  [['font-size', 'normal'],
   ['background-color', 'white !important'],
   ['-webkit-box-shadow', 'none']]),
 (["#test[src~='{a\\'bc}']",
   '.tester'],
  [['-webkit-transition', 'opacity 0.35s linear'],
   ['background', 'white !important url("abc\\"cd\'{e}.jpg")'],
   ['border-radius', '20px'],
   ['opacity', '0'],
   ['-webkit-box-shadow', 'rgba(0, 0, 0, 0.6) 0px 0px 18px']]),
 (['span'],
  [['display', 'block']]),
 (['.nothing'],
  [])]

Простое упражнение для читателя: напишите регулярное выражение дляудалить комментарии CSS (/* ... */).

1 голос
/ 04 февраля 2010

Что по этому поводу:

([#.]\S+\s*,?)+(?=\{)
0 голосов
/ 04 февраля 2010

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

  • селекторы потомков, такие как #someid ul img - все они являются допустимыми тегами и разделены пробелами
  • теги, которые не начинаются с . или # (т. Е. Имена тегов HTML) - вы должны предоставить список из них, чтобы соответствовать им, так как они не отличаются от атрибутов
  • комментарии
  • больше, о чем я не могу думать сейчас

Я думаю, что вместо этого вы должны рассмотреть какую-нибудь библиотеку CSS, подходящую для вашего предпочтительного языка.

0 голосов
/ 04 февраля 2010

Во-первых, я не вижу, как RE, который вы разместили, найдет .TB_Image#TB_window. Вы можете сделать что-то вроде:

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

При этом будут найдены вхождения # или . в начале строки, за которыми следует тег, за которым необязательно следует {, а затем перевод строки.

Обратите внимание, что это НЕ будет работать для таких строк, как .TB_Image { something: 0; } (все в одной строке) или div.mydivclass, поскольку . находится не в начале строки.

Редактировать : я не думаю, что вложенные скобки разрешены в CSS, поэтому, если вы прочитаете все данные и избавитесь от новых строк, вы можете сделать что-то вроде:

/([a-zA-Z0-9_\-]*([#\.][a-zA-Z0-9_\-]+)+\s*,?\s*)+{.*}/

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...