[英]Multi-line regex with overlapping matches
我正在使用一种工具来分析文件的CSS样式声明。 它使用了一个非常复杂的正则表达式,除了预期的性能问题和一些暂时不会影响我的小错误外,它正在做我想做的所有事情,除了一件事情。
我可以匹配元素名称,类,子类,伪类等的所有组合。但是,当一行包含多个声明时,我只能使其匹配一次。 举例来说,这是目前让我绊倒的事情:
td.class1, td.class2, td.class3
{
background-color: #FAFAFA;
height: 10px;
}
我可以编写一个满足所有三个声明都满足的表达式,但是由于我也在此之后捕获信息(方括号内的实际样式信息),因此我觉得整个文本块都应考虑在内,因此引擎将移至刚处理完的整个程序段之后的下一个字符。
有没有一种方法可以做到这一点,即每个类将是一个单独的匹配项,并且所有类都将包含随后的样式信息? 我知道我可以修改我的正则表达式以匹配整行,然后在获得匹配项后将其解析为逗号,但是我想尽可能将所有逻辑保留在表达式本身内。
如果与答案绝对相关,我可以发布用于生成它的表达式和/或注释的代码,但是表达式很大/很丑陋(因为所有非平凡的正则表达式都是这样),并且代码有点长。
您需要CSS解析器,而不是正则表达式。 您可能应该阅读C#是否有CSS解析器 。
这是一个与示例数据一起使用的正则表达式:
@"([^,{}\s]+(?:\s+[^,{}\s]+)*)(?=[^{}]*(\{[^{}]+\}))"
第一部分匹配并捕获组#1中的一个选择器(td.class1),然后超前跳过所有剩余的选择器并捕获组#2中的关联样式规则。 下次匹配尝试从上一次前瞻开始的地方开始,因此它匹配下一个选择器(td.class2),并且前瞻再次捕获相同的规则块。
这不会处理@-规则或注释,但在您提供的示例数据上可以正常工作。 我什至在一些真实的样式表上进行了检查,效果非常好。
根据正则表达式引擎的细微差别,您可以通过将捕获对象嵌入到前行中来实现此目的,例如:
\.(\w+)(?=.*?{([^}]*)})
我希望弄清楚比赛组的含义是一种练习。
对于正则表达式来说,这不是一个好问题。
另一方面,您肯定只需要几次传递就可以编写基本的CSS解析器。
毕竟,CSS语法只是[一些东西],[大括号],[其他东西],[大括号]。
您找到了这两个部分,您将第一个拆分为逗号,将第二个拆分为分号,您已经完成了很多工作。
我需要对AmbroseChapel所说的内容采取类似的看法,而我在AS3中也需要它,因此我分享了它,以防它对其他人有所帮助。 我试图做到周全,评论会引导您完成整个过程。 我已经在一些流行的CSS样板板上测试了它,并且效果很好。 :)(这仅用于列出选择器名称,而不用于属性解析。)
public function getSelectors( targetCSS:String, includeElements:Boolean = true ):ArrayCollection
{
var newSelectorCollection:ArrayCollection = new ArrayCollection();
if( targetCSS == null || targetCSS == "" ) return newSelectorCollection;
var newSelectors:Array = new Array();
var elements:Array = new Array();
var ids:Array = new Array();
var classes:Array = new Array();
// Remove comments
var cssString:String = "";
var commentParts:Array = targetCSS.split( "/*" );
for( var c:int = 0; c < commentParts.length; c++ ){
var comPart:String = commentParts[ c ] as String;
var comTestArray:Array = comPart.split( "*/" );
if( comTestArray.length > 1 ){
comTestArray.shift();
comPart = comTestArray.join( "" );
}
cssString += comPart;
}
// Remove \n
cssString = cssString.split( "\n" ).join( "" );
// Remove \t
cssString = cssString.split( "\t" ).join( "" );
// Split at }
var cssParts:Array = cssString.split( "}" );
for( var i:int = 0; i < cssParts.length; i++ ){
var cssPrt:String = cssParts[ i ] as String;
// Detect nesting such as media queries by finding more than one {
var nestingTestArray:Array = cssPrt.split( "{" );
// If there is nesting split at { then drop index 0 and re-join with {
if( nestingTestArray.length > 2 ){
nestingTestArray.shift();
cssPrt = nestingTestArray.join( "{" );
}
// Split at each item at {
var cssPrtArray:Array = cssPrt.split( "{" );
// Disregard anything after {
cssPrt = cssPrtArray[ 0 ] as String;
// Split at ,
var selectorList:Array = cssPrt.split( "," );
for( var j:int = 0; j < selectorList.length; j++ ){
var sel:String = selectorList[ j ] as String;
// Split at : and only keep index 0
var pseudoParts:Array = sel.split( ":" );
sel = pseudoParts[ 0 ] as String;
// Split at [ and only keep index 0
var attrQuryParts:Array = sel.split( "[" );
sel = attrQuryParts[ 0 ] as String;
// Split at spaces
var selectorNames:Array = sel.split( " " );
for( var k:int = 0; k < selectorNames.length; k++ ){
var selName:String = selectorNames[ k ] as String;
if( selName == null || selName == "" ){
continue;
}
// Check for direct class applications such as p.class-name
var selDotIndex:int = selName.indexOf( ".", 1 );
if( selDotIndex != -1 ){
// Add the extra classes
var dotParts:Array = selName.split( "." );
for( var d:int = 0; d < dotParts.length; d++ ){
var dotPrt:String = dotParts[ d ] as String;
if( d > 0 ){
dotPrt = "." + dotPrt;
if( d == 1 && selName.indexOf( "." ) === 0 ){
selName = dotPrt;
}else{
selectorNames.push( dotPrt );
}
}else{
if( dotPrt != "" ){
selName = dotPrt;
}
}
}
}
// Only add unique items
if( newSelectors.indexOf( selName ) == -1 ){
// Avoid @ prefix && avoid *
if( selName.charAt( 0 ) != "@" && selName != "*" ){
newSelectors.push( selName );
switch( selName.charAt( 0 ) ){
case ".":
classes.push( selName );
break;
case "#":
ids.push( selName );
break;
default:
elements.push( selName );
break;
}
}
}
}
}
}
if( includeElements ){
newSelectorCollection.source = elements.sort().concat( ids.sort().concat( classes.sort() ) );
}else{
newSelectorCollection.source = ids.sort().concat( classes.sort() );
}
return newSelectorCollection;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.