Regex для извлечения классов HTML5 из строки селектора CSS

1

Я читаю файлы CSS с диска как строки.

Моя цель - извлечь классы HTML в паре с определенным атрибутом данных, например:

.foo[data-my-attr] 

Атрибут data является достаточно уникальным, так что мне не нужно беспокоиться о пересечении CSS AST. Я могу просто использовать регулярное выражение следующим образом:

(\.\S+)+\[data-my-attr\]

Это уже работает, но \S+, очевидно, плохо подходит для соответствия классу HTML в селекторе. Он будет включать в себя различные комбинаторы, псевдоклассы, псевдоселекторы и т.д.

Я попытался создать версию регулярного выражения с белым списком, например (\w|-)+, но спецификация HTML5 для имен классов очень разрешительна. Это неизбежно, что либо я пропускаю определенные символы, либо включаю неправильные символы.

Какое регулярное выражение можно использовать для извлечения классов HTML5 из строки селектора CSS?

Я использую Node, т.е. JavaScript-код регулярных выражений.

UPD1

Некоторые примеры:

  • .foo[data-my-attr] - должен соответствовать .foo
  • .foo>span[data-my-attr] - не должен совпадать
  • .I_f%⌘ing__HTML5[data-my-attr] - должен соответствовать .I_f%⌘ing__HTML5

Этот вопрос существует, потому что я не могу думать о всех возможных допустимых классах HTML5. Мне нужно регулярное выражение, основанное на удивительно неопределенной спецификации класса HTML5:

3.2.5.7 Атрибут класса

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

Классы, назначенные ему элементом HTML, состоят из всех возвращаемых классов, когда значение атрибута класса разбивается на пробелы. (Дубликаты игнорируются.)

Нет никаких дополнительных ограничений на то, что авторы токенов могут использовать в атрибуте class, но авторам рекомендуется использовать значения, которые описывают характер контента, а не значения, которые описывают желаемую презентацию содержимого.

Очевидно, что класс не должен содержать пробелы и символы типа +>:()[]=~ потому что они являются частью синтаксиса селектора CSS...

  • 0
    Кто бы ни голосовал, чтобы закрыть вопрос, пожалуйста, объясните в комментариях, что можно исправить, чтобы сделать этот вопрос действительным.
  • 0
    Будет ли это регулярное выражение stackoverflow.com/a/6329126/1156518 дополнено вашим конкретным атрибутом для вас?
Показать ещё 7 комментариев

2 ответа

2

Вы не должны использовать регулярное выражение.

Более твердая альтернатива - PostCSS (и его синтаксический анализатор). С его помощью вы получите полное AST (абстрактное синтаксическое дерево) всей таблицы стилей, с помощью которой вы сможете легко извлечь часть, которую ищете.

const postcss = require('postcss');
const Tokenizer = require('css-selector-tokenizer');

let output = [];

const postcssAttributes = postcss.plugin('postcss-attributes', function() {
  return function(css) {
    css.walkRules(function(rule) {
      rule.selectors.map(selector => {
        const tokenized = Tokenizer.parse(selector);
        if (
          tokenized.nodes.some(({ nodes }) =>
            nodes.some(
              node =>
                node.type === 'attribute' && node.content === 'data-my-attr'
            )
          )
        ) {
          output.push(selector);
        }
      });
    });
  };
});

const css = '
    .foo[data-my-attr] {
        color: red;
    }
    .foo[something] {
        color: red;
    }
';

postcss([postcssAttributes])
  .process(css)
  .then(result => console.log(output));

// logs: [ '.foo[data-my-attr]' ]

Это будет записывать все соответствующие селекторы.

  • 0
    Спасибо за ваш пример. Я подумывал об использовании CSS AST и решил отказаться от него по двум причинам: 1. Это увеличит время сборки. 2. Это не решает проблему извлечения классов HTML из составных селекторов, которые по-прежнему требуют регулярных выражений.
  • 0
    Мой пример поддерживает составные селекторы
0

Регулярное выражение для соответствия классу HTML5 в селекторной строке:

/\.-?(?:[_a-z]|[\240-\377]|(?:(:?\\[0-9a-f]{1,6}(\r\n|[ \t\r\n\f])?)|\\[^\r\n\f0-9a-f]))(?:[_a-z0-9-]|[\240-\377]|(?:(:?\\[0-9a-f]{1,6}(\r\n|[ \t\r\n\f])?)|\\[^\r\n\f0-9a-f]))*/

Кредит: @KOBA789

спасибо to Alohci для указания в правильном направлении.

  • 0
    В самом деле? Как насчет #notaclass:after { content:".notaclasstoo { whatever you want"; }
  • 0
    @CasimiretHippolyte Ваш пример не является допустимым селектором.
Показать ещё 4 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню