我正在尝试匹配SCSS字符串中使用的函数或mixin,因此我可能会删除它,但我遇到了一些麻烦。
对于那些不熟悉SCSS的人来说,这是我试图匹配的东西的一个例子(来自bootstrap 4)。
@mixin _assert-ascending($map, $map-name) {
$prev-key: null;
$prev-num: null;
@each $key, $num in $map {
@if $prev-num == null {
// Do nothing
} @else if not comparable($prev-num, $num) {
@warn "Potentially invalid value for #{$map-name}: This map must be in ascending order, but key '#{$key}' has value #{$num} whose unit makes it incomparable to #{$prev-num}, the value of the previous key '#{$prev-key}' !";
} @else if $prev-num >= $num {
@warn "Invalid value for #{$map-name}: This map must be in ascending order, but key '#{$key}' has value #{$num} which isn't greater than #{$prev-num}, the value of the previous key '#{$prev-key}' !";
}
$prev-key: $key;
$prev-num: $num;
}
}和一个小函数:
@function str-replace($string, $search, $replace: "") {
$index: str-index($string, $search);
@if $index {
@return str-slice($string, 1, $index - 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace);
}
@return $string;
}到目前为止,我有以下正则表达式:
@(function|mixin)\s?[[:print:]]+\n?([^\}]+)然而,它只匹配到它找到的第一个},这导致它失败,这是因为它需要找到最后一个出现的右大括号。
我的想法是,能够匹配函数定义的正则表达式是可以修改的,但我使用Google foo找不到一个好的正则表达式!
提前感谢!
发布于 2017-05-31 15:33:24
我不建议使用正则表达式,因为正则表达式不能处理递归,在这种情况下您可能需要处理递归。
例如:
@mixin test {
body {
}
}包括两个»级别«的scope here ({{ }}),因此您的正则表达式应该能够在括号打开和关闭时对它们进行计数,以匹配mixin或函数的结尾。但对于正则表达式,这是不可能的。
此正则表达式
/@mixin(.|\s)*\}/gm将匹配整个混合,但如果输入是这样的:
@mixin foo { … }
body { … }它将匹配直到最后一个}为止的所有内容,其中包括主体的样式定义。这是因为正则表达式无法知道哪个}关闭了mixin。
看看this answer,它解释了或多或少相同的事情,但基于匹配的html元素。
相反,您应该使用解析器将整个样式表解析为语法树,然后删除不需要的函数,然后再次将其写入字符串。
发布于 2017-05-31 15:52:36
事实上,正如@philipp所说,正则表达式不能像编译器那样取代语法分析。
但这里有一个sed命令,它有点难看,但可以解决这个问题:
sed -r -e ':a' -e 'N' -e '$!ba' -e 's/\n//g' -e 's/}\s*@(function|mixin)/}\n@\1/g' -e 's/^@(function|mixin)\s*str-replace(\s|\()+.*}$//gm' <your file>
-e ':a' -e 'N' -e '$!ba' -e 's/\n//g':读取循环中的所有文件并删除新行(有关更多信息,请参见information)-e 's/}\s*@(function|mixin)/}\n@\1/g':使每个@mixin或@function语句成为新行的开始,并将前面的}作为上一条语句的最后一个字符:删除与@function str-replace或@mixin str-replace声明对应的行但它将导致输出松散缩进,因此您必须在那之后重新缩进它。
我在一个文件上尝试了它,其中我多次复制/粘贴了您提供的示例代码,因此您必须在您的文件上尝试它,因为在某些情况下,regex可能会匹配比所需更多的元素。如果是这样,请为我们提供一个测试文件来尝试解决这些问题。
发布于 2017-05-31 22:12:12
在经历了许多头痛之后,这是我问题的答案!
源代码需要逐行拆分并读取,维护左/右大括号的计数以确定索引何时为0。
$pattern = '/(?<remove>@(function|mixin)\s?[\w-]+[$,:"\'()\s\w\d]+)/';
$subject = file_get_contents('vendor/twbs/bootstrap/scss/_variables.scss'); // just a regular SCSS file containing what I've already posted.
$lines = explode("\n",$subject);
$total_lines = count($lines);
foreach($lines as $line_no=>$line) {
if(preg_match($pattern,$line,$matches)) {
$match = $matches['remove'];
$counter = 0;
$open_braces = $closed_braces = 0;
for($i=$line_no;$i<$total_lines;$i++) {
$current = $lines[$i];
$open_braces = substr_count($current,"{");
$closed_braces = substr_count($current,"}");
$counter += ($open_braces - $closed_braces);
if($counter==0) {
$start = $line_no;
$end = $i;
foreach(range($start,$end) as $a) {
unset($lines[$a]);
} // end foreach(range)
break; // break out of this if!
} // end for loop
} // end preg_match
} // endforeach我们有一个没有任何函数或混合的$lines数组。
可能有一种更好的方法可以做到这一点,但我没有时间或意愿为SCSS编写AST解析器
然而,这可以很容易地修改为一个被黑客攻击的代码!
https://stackoverflow.com/questions/44278016
复制相似问题