使用正则表达式检查字符串是否为有效的CSS

7

我需要检查用户输入是否为有效的CSS语法(输入字符串基本上是一个CSS文件)。它可以包含类、选择器、!important等。

我没有开始工作,因为我希望已经有一些正则表达式语法可用,这样我就不必从头开始。

我尝试过谷歌搜索,但我找到的都是部分匹配的字符串,而不是验证所有可能的CSS的正则表达式。


7
我怀疑正则表达式可以做到这一点。它不是一个“正则”的语言。 - TypeIA
是的,我尝试过了,但所有的结果都让我在 CSS 文件中查找特定属性,而不是验证整个样式表。 - Shimmy Weitzhandler
1
你最好使用 CSS 解析器,例如:https://github.com/reworkcss/css-parse - steveax
1
首先,您使用的是哪种编程语言?其次,您是否计划支持高级CSS功能,例如媒体查询、动画、过渡等?.test{ fail:red;}是有效的吗? - HamZa
1
我认为这可能是有可能的,但天哪!这将是一个非常复杂的正则表达式,有许多变化。我认为应该从引用这个开始..http://www.w3.org/TR/css3-syntax/#detailed-grammar。如果有人能够付出足够的努力制作一个足够的正则表达式来验证有效的CSS语法,同时在正确的错误CSS语法上返回false,那么我会非常印象深刻。 - Bryan Elliott
2个回答

9

好的,我想出了一个匹配有效CSS样式的正则表达式。

([#.@]?[\w.:> ]+)[\s]{[\r\n]?([A-Za-z\- \r\n\t]+[:][\s]*[\w .\/()\-!]+;[\r\n]*(?:[A-Za-z\- \r\n\t]+[:][\s]*[\w .\/()\-!]+;[\r\n]*(?2)*)*)}

这里有一个工作示例:

http://regex101.com/r/fK9mY3

请注意... 在查看上面的示例链接后,您会发现这个正则表达式适用于常见的基本CSS2样式,但是,为了匹配所有CSS3样式变化,涉及到http://www.w3.org/TR/css3-syntax/#detailed-grammar,这个正则表达式需要进行一些调整... 上面的正则表达式是一个起点..


1
url()中不允许使用完整的URL。 - Dalin
2
这就是正则表达式的陷阱:它们的复杂性很大,除非您能考虑到所有条件...更糟糕的是,由于标准仍在不断发展,所以这个答案越旧,就越不可靠。尽管付出了巨大的努力,但这应该被编写为一个完整的函数,并带有易于更新的 if 条件。 - John
1
@John,完全同意。正则表达式只是一个起点,因为CSS标准不断发展,更好的解决方案是将这个正则表达式与其他一些边缘情况的正则表达式匹配结合起来,并打包成JS库。当然,它需要不断地维护。 - Bryan Elliott
@BryanElliott 在他下面的回答中使用了对这个问题的双重改变,我也在他的回答下面的评论中做了一些改变,我还有一个最后的问题需要解决,如果你知道如何解决,请告诉我好吗?谢谢。 - undefined

3

对Bryan的回答进行补充,并添加一条注释

  • JavaScript支持: 出现了错误 (?2)
  • 多类名: .class, .class2 {...}
  • 类名分隔符: .class-name, .class_name
  • 空类名: .class {}
  • 百分比: 宽度:100%;
  • 带引号的url地址: 背景:url("/img.jpg");
const multi = /((?:^\s*)([\w#.@*,:\-.:>,*\s]+)\s*{(?:[\s]*)((?:[A-Za-z\- \s]+[:]\s*['"0-9\w .,\/()\-!%]+;?)*)*\s*}(?:\s*))/mi

const example = `
div.css-class-10_9::hover, .active {
  width: 100%;
  background: rgba(1.0,0,1,1); 
  background-url: url("http://img.jpg");   
}

div.css-class-10_9::hover,
.active {
  width: 100%;
  background: rgba(1.0,0,1,1);
  background-url: url("http://img.jpg");
}

html {
  background: white;
}
`

let out = example.replace(multi, '')
// "
// div.css-class-... {...}
// html {...}
// "

out = out.replace(multi, '')
// "html {...}"

out = out.replace(multi, '')
// ""

您可以使用 global 来一次性替换全部。
const global_re = /((?:^\s*)([\w#.@*,:\-.:>,*\s]+)\s*{(?:[\s]*)((?:[A-Za-z\- \s]+[:]\s*['"0-9\w .,\/()\-!%]+;?)*)*\s*}(?:\s*))/gmi


example.replace(global_re, '');
// ""


example.replace(global_re,'$1') // group 1 all css
//
// div.css-class-...{
//   width...
//   rest_css...
// }
//
// ...
//
// html {
//   ...
// }

类名

example.replace(global_re,'$2\n\n') // group 1 all class names
// "
// div.css-class-10_9::hover, .active 
// 
// div.css-class-10_9::hover,
// .active 
// 
// html  
// "

类主体(替换除类主体外的所有内容)
example.replace(global_re,'$3\n')
// "
// width: 100%;
// background: rgba(1.0,0,1,1); 
// background-url: url("http://img.jpg");   
// 
// 
// width: 100%;
// background: rgba(1.0,0,1,1);
// background-url: url("http://img.jpg");
// 
// 
// background: white;
// 
// "

https://regex101.com/r/fK9mY3/55

(免责声明:这绝对不是验证 CSS 的方法)

例如:'............a {}' 将返回 true。


为了“改进”这个,我添加了一些更多的选择器选项(+和~),并且移除了^作为选择器前面的行的开始,这样可以选择任何没有空格的压缩的CSS。我对正则表达式并不是很了解,所以可能会有问题,但是我想分享一下。现在我唯一的问题是在URL中的base64数据。它在样式值中的“;”处失败。在添加了这个字符之后,它超时了。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接