使用正则表达式查找不在评论中的 CSS class 个名称

Find CSS class names that are not inside comments using Regular Expressions

我正在尝试替换 CSS 文件中的所有 class 名称。我正在使用 JavaScript/Node.js.

我目前的解决方案是:/\.[a-z][a-z0-9-_]*/g。 文件末尾是引用源映射文件的注释:/*# sourceMappingURL=style.css.map */。现在 URL 的文件扩展名也被替换了。

给定以下输入:

.text-center { text-align: center; }
table.simple{background:#fff;}.bg-white{background:#fff;}
/*# sourceMappingURL=style.css.map */
/*
Example comment file.css
*/

结果是:

.a { text-align: center; }
table.a{background:#fff;}.a{background:#fff;}
/*# sourceMappingURL=style.a.a */
/*
Example comment file.a
*/

我想要的是:

.a { text-align: center; }
table.a{background:#fff;}.a{background:#fff;}
/*# sourceMappingURL=style.css.map */
/*
Example comment file.css
*/

我该如何更改我的正则表达式,使其只匹配评论之外的 class 个名称(// 评论与此处无关)?

使用以下正则表达式,您应该能够从 css 文件中提取所有 class-名称,这些名称未在注释中。 class 名称以点 (.)

开头很重要

正则表达式:

/^.[a-z][a-z0-9-_].*?[\s]/mg

我已经在 pcre flavor

中使用以下 RegEx
/(\/\*)?(?(1)(.*\*\/)|(\.[a-z][a-z0-9-_]*))/g

我正在使用条件语句。每当它检测到评论的开头时,它不会查找 class 名称,而是查找评论的结尾。但是,这不适用于多行评论。 class 名称是第三个捕获组。所以要替换 class 名称,只触摸包含捕获组 3.

的匹配项

我没有注意到我在 regex101.com 上使用的是 pcre 而不是 javascript,结果我的 JS 代码出现语法错误。我现在正在努力寻找适用于 JS 的解决方案。

编辑:

我现在把它移植到 JS:

/(?=\/\*)|(\.[a-z][a-z0-9-_]*)(?!.*\*\/)/g

我仍然需要找到一种方法让它与多行一起工作。

试试这个正则表达式:

\.[^{\s]*(?=\s*{)

并将每个匹配项替换为 .a

Click for Demo

解释:

  • \. - 匹配 .
  • [^{\n]* - 匹配 0+ 次既不是 white-space 也不是 {
  • 的任何字符
  • (?=\s*{) - 正向前瞻以确保当前位置后跟 0+ 个空格后跟 {.

现在,如果我们有

格式的评论,上面的正则表达式将失败
/*# sourceMappingURL=style.css.map {*/

{ 出现在评论中的 css.map 之后。因此,要处理这种情况,您可以使用以下正则表达式(与前面的正则表达式几乎相似。只是对正则表达式再进行一次负面预测)

\.[^{\s]*(?=\s*{)(?!(?:(?!\/\*)[\s\S])*\*\/)

Click for Demo

解释:

  • \.[^{\s]*(?=\s*{) - 类似于前面的正则表达式
  • (?!(?:(?!\/\*)[\s\S])*\*\/) - 否定前瞻以确保当前位置(.classname 之后的位置)不存在于 /*...*/ 形式的注释中
    • (?!.... - 否定前瞻
    • (?:(?!\/\*)[\s\S])* - 贪婪地匹配 0+ 次出现的任何字符,这些字符不以序列 /*
    • 开头
    • \*\/ - 匹配 */

这两种方法适用于不同的情况,例如 ID 之间的 classes 或选择中的多个 classes:

.class-a, #id-a, .class-b:hover {}

第一种方法

在第一种方法中,您可以匹配评论部分和 CSS classes,然后在匹配时替换 class 名称并保持评论不变:

\/\*[\s\S]*?\*\/|(\.[a-z_-][\w-]*)(?=[^{}]*{)
^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 Match comments    Match and capture classes

细分:

\/\*[\s\S]*?\*\/    # Match a comment block
|                   # Or
(                   # Start of capturing group #1
    \.[a-z_-][\w-]* # Match a CSS class name
)                   # End of CG #1
(?=                 # Start of a positive lookahead
    [^{}]*{         # Class should be followed by a `{` (may not be immediately)
)                   # End of lookahead

JS代码:

var str = `.text-center { text-align: center; }
table.simple{background:#fff;}.bg-white{background:#fff;}
/*# sourceMappingURL=style.css.map */
/*
Example comment file.css
*/`

console.log(str.replace(/\/\*[\s\S]*?\*\/|(\.[a-z_-][\w-]*)(?=[^{}]*{[^{}]*})/g,
    function([=13=], ) {
        return  ? '.a' : [=13=]; // If a class is matched ...
    }
));

第二种方法

如果您认为评论中不会出现这样的情况:

/* style.css {css file} */

您可以在第一种方法中省略匹配注释:

\.[a-z_-][\w-]*(?=[^{}]*{[^{}]*})
                         ^^^^^^^ 
             Added for a more strict selection

RegEx live demo

JS代码:

var str = `.text-center { text-align: center; }
table.simple{background:#fff;}.bg-white{background:#fff;}
/*# sourceMappingURL=style.css.map */
/*
Example comment file.css
*/`

console.log(str.replace(/\.[a-z_-][\w-]*(?=[^{}]*{[^{}]*})/g, '.a'));