20

我想解析一个 CSS 文件并在每个 CSS 选择器之前添加另一个 CSS 选择器。

从:

p{margin:0 0 10px;}
.lead{margin-bottom:20px;font-size:21px;font-weight:200;line-height:30px;}

我想要:

.mySelector p{margin:0 0 10px;}
.mySelector .lead{margin-bottom:20px;font-size:21px;font-weight:200;line-height:30px;}

但是我的 CSS 文件真的很复杂(实际上它是引导 CSS 文件),所以正则表达式应该匹配所有的 CSS 选择器。

现在,我有这个正则表达式:

([^\r\n,{};]+)(,|{)

你可以在这里看到结果http://regexr.com?328ps,但是正如你所看到的,有很多不应该匹配的匹配。

例如:

text-shadow:0 -1px 0 rgba(0,

匹配阳性,但不应该

有人有解决方案吗?

4

10 回答 10

30

没有一个。CSS 选择器不是“正则语言”的示例,因此不能被正则表达式解析。您需要根据 CSS 语法规范构建自己的解析器:http: //www.w3.org/TR/css3-syntax/#detailed-grammar

CSS 被描述为 LL(1) 语法,因此您最好使用像 Yacc 这样的工具来为您生成解析器。

于 2012-09-25T03:36:41.210 回答
26

所以我终于找到了一个适合我要求的正则表达式

([^\r\n,{}]+)(,(?=[^}]*{)|\s*{)

关键是添加一个积极的前瞻以避免错误的匹配

(?=[^}]*{)

你可以在这里看到结果:http ://regexr.com?328s7

我可以推荐的唯一预防措施是删除每个块评论:

于 2012-09-25T07:36:56.047 回答
6

所以最后我找到了一种更好的方法来做到这一点。

我使用 LESS 编辑器(例如: http: //lesstester.com/

并简单地嵌套我的整个 css 文件: .mySelector{ your css here }

于 2013-11-18T04:58:06.960 回答
3

确实不能使用 regex 选择 css选择器,但是可以使用 regex 选择 css规则,因此可以以相反的方式完成工作:

  1. 格式化 css 文件,以便在同一行中没有选择器和规则。您的代码应如下所示:

    p{
    边距:0 0 10px;
    }
    .lead{
    边距底部:20px;
    字体大小:21px;
    字体粗细:200;
    行高:30px;
    }

  2. 选择所有规则(正则表达式:(^(.)*;)

    p{
    边距:0 0 10px;
    }
    .lead{
    边距底部:20px;
    字体大小:21px;
    字体粗细:200;
    行高:30px;

    }

  3. 为规则添加一些前缀(例如####)

    p{
    ####margin:0 0 10px;
    }
    .lead{
    ####margin-bottom:20px;
    ####字体大小:21px;
    ####字体重量:200;
    ####行高:30px;

    }

  4. 选择所有不以 #### 开头的行,而不是返回行,而不是 }(正则表达式:^[^#### \n }])

    p{
    ####margin:0 0 10px;
    }
    .lead{
    ####margin-bottom:20px;
    ####字体大小:21px;
    ####字体重量:200;
    ####行高:30px;
    }

  5. 添加你的CSS前缀

    .my_class_prefix p{
    ####margin:0 0 10px;
    }
    .my_class_prefix .lead{
    ####margin-bottom:20px;
    ####字体大小:21px;
    ####字体重量:200;
    ####行高:30px;
    }

  6. 删除添加的前缀####

    .my_class_prefix p{
    边距:0 0 10px;
    }
    .my_class_prefix .lead{
    边距底部:20px;
    字体大小:21px;
    字体粗细:200;
    行高:30px;
    }

于 2014-09-16T15:13:23.650 回答
2

一个简单易读的正则表达式如下:

[\#\.\w\-\,\s\n\r\t:]+(?=\s*\{)

您可以在此工具中的 css 代码上对其进行测试`

于 2014-08-28T15:12:27.030 回答
1

遇到了类似的问题,并使用以下内容仅提取 CSS 选择器和指令,而无需注释和媒体查询:

/^(?!.*@media)[\t ]*([a-zA-Z#.:*\[][^{\/]*\s*){[\s\S]*?}/

示例:https ://regex101.com/r/JmjthP/5

我确定它缺少一些边缘情况,但似乎对我有用。

看到这个问题:Ruby RegExp - 匹配所有 CSS 选择器和指令

于 2018-09-26T15:40:37.960 回答
1

这就是我想出的:

(?<=\s)[^ ]*\s*\{[^\}]+\:[^\}]+\}

于 2020-10-04T20:04:14.903 回答
0

这是我用于类似问题的解决方案。我想删除所有以@. 为此,我使用了以下正则表达式:

@\s*.*\s*\{((?!\n\})[\s\S])+\n\}

它假设规则以新行结束。这样它就可以处理嵌套的 CSS 规则。

于 2016-12-02T13:06:29.743 回答
0

有趣的讨论 - 不是纯粹的 reg exp 而是一个非常短的 JS 函数:

function cssNester(css, nestWith) {
  let kframes = [];
  css = css.replace(/@(-moz-|-webkit-|-ms-)*keyframes\s(.*?){([0-9%a-zA-Z,\s.]*{(.*?)})*[\s\n]*}/g, x => kframes.push(x) && '__keyframes__');
  css = css.replace(/([^\r\n,{}]+)(,(?=[^}]*{)|\s*{)/g, x => x.trim()[0] === '@' ? x : x.replace(/(\s*)/, '$1' + nestWith + ' '));
  return '/*' + nestWith + '*/\n' + css.replace(/__keyframes__/g, x => kframes.shift());
}
于 2021-05-13T10:39:46.710 回答
0

虽然不可能编写一个匹配任何有效 CSS 选择器的正则表达式,但您可以结合几个正则表达式和一些逻辑来实现您的目标。

以下使用 Node 的fs模块来读取 CSS,但您可以根据需要获取原始 CSS 字符串。

const fs = require('fs'),
    myClassName = 'mySelector',
    mySelector = '.' + myClassName,
    mySelectorRegex = new RegExp(`\\.${myClassName}([ .#[:(]|$)`),
    cssSelectorRegex = /[@.#a-zA-Z][^}]*?(?={)/g;

let css = fs.readFileSync('path/to/file.css').toString();

css = css.replace(cssSelectorRegex, match => {

    // Match is a string of selectors like '.foo' or '.foo, #bar'
    // We need to split it on the comma and handle each selector individually
    return match.split(',').map(selector => {

        selector = selector.trim();

        // Don't alter media queries, imports, or selectors that already contain '.mySelector'
        if (selector.startsWith('@') || selector.match(mySelectorRegex)) {

            return selector;

        }

        // Prepend '.mySelector ' to the selector
        return mySelector + ' ' + selector;

    // Combine the list of selectors back together
    }).join(',');

});
于 2018-10-09T18:27:59.697 回答