我正在寻找能够可靠地匹配媒体查询及其内容的正则表达式(在PHP PCRE中),包括媒体查询主体为空的奇怪情况。源文本可能是:
@media only screen {
p {
color:red;
}
}
@media only screen and (max-width: 596px) {
p {
color:blue;
}
img {
max-width: 200px;
}
}
@media only screen {
}
img {
display: block;
}
@media only screen and (max-width: 240px) {
p {
color:green;
}
}
p {
font-weight: normal;
}
我想将每个媒体查询及其CSS主体捕获为子模式,因此我最终得到一个PHP数组,如:
[['@media only screen {
p {
color:red;
}
}','p {
color:red;
}'],...]
关键是这需要一个递归或子程序模式来平衡大括号。空查询足以混淆this question中的模式,因为它无法区分css规则的结尾和空媒体查询的结尾:
/@media[^{]+\{([\s\S]+?\})\s*\}/
我一直在尝试并且未能使用this article中的建议来制作(b(?:m|(?1))*e)
形式的模式,其中b
是构造的开头,{{1是构造中间可能发生的事情,m
是最后可能发生的事情,并且它们都不能匹配相同的东西。
因此,e
应为b
,@media[^{]+\{
应为e
,而\}
需要使用CSS规则,可能是m
,给我:
([^{]+?\{[^}]*?\s*\})
然而,这不起作用,所以我有点迷失。任何人都可以提出有效的模式吗?
我已经设置了正则表达式测试here。
或者,非正则表达式解析器可能会更好。
请注意,我一般不尝试验证或匹配CSS选择器(不是正则表达式的作业),只需抓取查询及其正文的内容。
更新添加了更多示例内容,解释了我想要了解的内容。
答案 0 :(得分:3)
如果您确定要匹配的块总是具有平衡数量的大括号,则可以使用带有子例程的正则表达式:
'~@media\b[^{]*({((?:[^{}]+|(?1))*)})~'
请参阅regex demo
这是一个IDEONE demo:
$re = '~@media\b[^{]*({((?:[^{}]+|(?1))*)})~';
$str = "@media only screen {\n p {\n color:red;\n }\n}\n@media only screen and (max-width: 596px) {\n p {\n color:blue;\n }\n img {\n max-width: 200px;\n }\n}\n@media only screen {\n\n}\nimg {\n display: block;\n}\n@media only screen and (max-width: 240px) {\n p {\n color:green;\n }\n}\np {\n font-weight: normal;\n}";
preg_match_all($re, $str, $matches, PREG_PATTERN_ORDER);
print_r($matches[0]);
print_r($matches[2]);
模式详情:
@media\b
- 匹配@media
作为整个单词(因为\b
是单词边界)[^{]*
- 匹配{
({((?:[^{}]+|(?1))*)})
- 捕获组#1捕获平衡号为{...}
和{
的{{1}}块(注意它是一个技术组,我们需要递归此组子模式,以便正确匹配}
s)。它匹配...
{...}
- 一个大括号{
- 第2组(平衡((?:[^{}]+|(?1))*)
内)匹配的内容
{...}
- [^{}]+
和{
以外的1个以上字符(因为我们需要匹配不是前导和尾随分隔符的所有内容)}
- 或...... |
- 整个第1组子模式(?1)
- 一个大括号请注意}
可以使用preg_match_all('~\s*(\w+)\s*{\s*([^}]*?)\s*}~', $matches[2], $subblocks)
模式进一步处理。