Я читаю файлы CSS с диска как строки.
Моя цель - извлечь классы HTML в паре с определенным атрибутом данных, например:
.foo[data-my-attr]
Атрибут data является достаточно уникальным, так что мне не нужно беспокоиться о пересечении CSS AST. Я могу просто использовать регулярное выражение следующим образом:
(\.\S+)+\[data-my-attr\]
Это уже работает, но \S+
, очевидно, плохо подходит для соответствия классу HTML в селекторе. Он будет включать в себя различные комбинаторы, псевдоклассы, псевдоселекторы и т.д.
Я попытался создать версию регулярного выражения с белым списком, например (\w|-)+
, но спецификация HTML5 для имен классов очень разрешительна. Это неизбежно, что либо я пропускаю определенные символы, либо включаю неправильные символы.
Какое регулярное выражение можно использовать для извлечения классов HTML5 из строки селектора CSS?
Я использую Node, т.е. JavaScript-код регулярных выражений.
Некоторые примеры:
.foo[data-my-attr]
- должен соответствовать .foo
.foo>span[data-my-attr]
- не должен совпадать.I_f%⌘ing__HTML5[data-my-attr]
- должен соответствовать .I_f%⌘ing__HTML5
Этот вопрос существует, потому что я не могу думать о всех возможных допустимых классах HTML5. Мне нужно регулярное выражение, основанное на удивительно неопределенной спецификации класса HTML5:
Атрибут, если указан, должен иметь значение, представляющее собой набор разделенных пространством токенов, представляющих различные классы, к которым принадлежит элемент.
Классы, назначенные ему элементом HTML, состоят из всех возвращаемых классов, когда значение атрибута класса разбивается на пробелы. (Дубликаты игнорируются.)
Нет никаких дополнительных ограничений на то, что авторы токенов могут использовать в атрибуте class, но авторам рекомендуется использовать значения, которые описывают характер контента, а не значения, которые описывают желаемую презентацию содержимого.
Очевидно, что класс не должен содержать пробелы и символы типа +>:()[]=~
потому что они являются частью синтаксиса селектора CSS...
Вы не должны использовать регулярное выражение.
Более твердая альтернатива - 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]' ]
Это будет записывать все соответствующие селекторы.
Регулярное выражение для соответствия классу 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 для указания в правильном направлении.
#notaclass:after { content:".notaclasstoo { whatever you want"; }