【问题标题】:Multi-line regex with overlapping matches具有重叠匹配的多行正则表达式
【发布时间】:2009-04-17 21:12:25
【问题描述】:

我正在开发一种工具来解析文件以获取 CSS 样式声明。它使用了一个非常复杂的正则表达式,除了预期的性能问题和一些暂时不影响我的小错误之外,它正在做我想做的所有事情,除了一件事。

我让它匹配元素名称、类、子类、伪类等的所有组合。但是,当一行包含多个声明时,我只能让它匹配一次。举个例子,目前让我感到不安的事情是这样的:

td.class1, td.class2, td.class3
{
    background-color: #FAFAFA;
    height: 10px;
}

我可以编写一个满足所有三个声明的表达式,但由于我还在它后面捕获信息(括号内的实际样式信息),我觉得这整个文本块都被考虑在内因此,引擎会继续处理刚刚处理的整个块之后的下一个字符。

有没有办法做到这一点,每个类都将是一个单独的匹配项,并且所有类都将包含以下样式信息?我知道我可以修改我的正则表达式以匹配整行,然后在我得到匹配后将其解析为逗号,但如果可能的话,我想将我的所有逻辑保留在表达式本身中。

如果表达式和/或我用来生成它的注释代码与答案绝对相关,我可以发布它,但表达式很大/丑陋(就像所有重要的正则表达式一样)并且代码有点冗长.

【问题讨论】:

    标签: c# .net css regex


    【解决方案1】:

    这是一个适用于您的示例数据的正则表达式:

    @"([^,{}\s]+(?:\s+[^,{}\s]+)*)(?=[^{}]*(\{[^{}]+\}))"
    

    第一部分匹配并捕获组 #1 中的选择器 (td.class1),然后前瞻跳过任何剩余的选择器并捕获组 #2 中的关联样式规则。下一次匹配尝试从前一次开始的地方开始,因此它匹配下一个选择器 (td.class2),并且前瞻再次捕获相同的规则块。

    这不会处理@-rules 或 cmets,但它适用于您提供的示例数据。我什至在一些真实世界的样式表上检查了它,它做得非常好。

    【讨论】:

    • 谢谢。与 Chaos 的回答类似,解决方案是捕捉未来的内容。我给了你接受的答案,因为你的正则表达式实际上适用于我扔给它的各种样本数据(并且极大地简化了我这样做的方式)。无论如何,我都会在处理之前剥离 cmets,所以现在看起来一切都很好。
    【解决方案2】:

    您需要一个 CSS 解析器,而不是一个正则表达式。您可能应该阅读Is there a CSS Parser for C#

    【讨论】:

      【解决方案3】:

      根据您的正则表达式引擎的细微差别,您可以通过在前瞻中嵌入捕获括号来做到这一点,例如:

      \.(\w+)(?=.*?{([^}]*)})
      

      我希望弄清楚匹配组的含义是一项相当大的练习。

      【讨论】:

      • 可以命名匹配组,而这正是我已经在做的。我可以匹配并提取类名和类主体……这不是问题。我的问题是我正在寻找一种方法来匹配共享一个共同主体的多个类名。我可能做不到,所以我将匹配整行并以逗号分隔。
      • 对,我的意思是,使用上述模式应该为您做到这一点,如果在前瞻中的捕获有效。前瞻性所做的是允许您向前扫描到类主体并(如果捕获有效)提取它,而不向前移动正则表达式的实际当前位置,因此它可以继续继续匹配类名。
      • 您的模式不完全匹配,但在前瞻中捕获的想法最终奏效了。我一开始没明白。 +1
      【解决方案4】:

      这对正则表达式来说不是一个好问题。

      另一方面,当然,您只需要几遍就可以编写一个基本的 CSS 解析器。

      CSS 语法毕竟只是[一些东西]、[打开花括号]、[一些其他东西]、[关闭花括号]。

      你找到那两块东西,你把第一块用逗号分开,第二块用分号分开,你就大功告成了。

      【讨论】:

      • 这是一个很好、简单的问题描述,我必须按照这些思路构建一些东西。
      【解决方案5】:

      我需要与 AmbroseChapel 所说的观点相似,并且我在 AS3 中需要它,所以我分享它以防它对其他人有所帮助。我试图做到彻底,cmets 会引导您完成整个过程。我已经在一些流行的 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;
      
          }
      

      【讨论】:

        猜你喜欢
        • 2012-04-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-09-24
        • 2017-11-10
        • 1970-01-01
        相关资源
        最近更新 更多