2009-04-17 85 views
1

我正在研究解析CSS樣式聲明文件的工具。它使用了一個非常複雜的正則表達式,除了預期的性能問題和一些現在不影響我的小錯誤之外,我正在做所有我希望它做的事情,除了一件事情。重疊匹配的多行正則表達式

我把它匹配的元素的名稱,類別,子類,僞類等的所有組合然而,當行包含不止一個聲明,我只能得到它匹配一次。作爲一個例子,這裏的東西是絆倒我此刻的那種:

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

我能寫,能滿足這所有三個聲明的表達,但因爲我也是經過捕獲信息它(括號內的實際樣式信息)我覺得整個文本塊被認爲是佔了的,因此引擎會移動到剛處理過的整個塊之後的下一個字符。

有沒有辦法做到這一點,每個類將是一個單獨的比賽,並都將包括如下以及風格的信息?我知道我可以修改我的正則表達式來匹配整行,然後在得到我的匹配之後解析它的逗號,但如果可能的話,我想將所有邏輯保留在表達式本身內。

如果它與答案是絕對相關的,但是表達式是巨大/醜陋的(因爲所有非平凡的正則表達式都是這樣)並且代碼是一點點的,我可以發佈表達式和/或用於生成它的註釋代碼冗長。

回答

2

這裏是與您的樣本數據工作的正則表達式:

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

第一部分比賽和捕獲組#1的選擇器(td.class1),然後先行跳過任何剩餘的選擇和捕捉關聯的組#2中的樣式規則。下一次匹配嘗試從前一次開始的前瞻開始,因此它匹配下一個選擇器(td.class2),並且預見再次捕獲同一個規則塊。

這不會處理@ -rules或評論,但它工作正常您提供的樣本數據。我甚至在一些真實世界的樣式表中檢查過它,它的表現非常好。

1

根據您的正則表達式引擎的細微差別深,您可以通過在向前看符號嵌入捕獲括號,即像這樣做:

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

我期望找出匹配羣體的意義是一個相當的練習。

+0

匹配組可以被命名,而這正是我已經在做的。我可以匹配並提取類名和類體......這不是問題。我的問題是,我正在尋找一種方法來匹配多個共享公共主體的類名。我可能無法做到,所以我會匹配整條線並在逗號處分割。 – Rich 2009-04-17 21:41:41

+1

沒錯,我要說的是,使用像上面那樣的模式應該爲你做這件事, lookahead正在做的是允許你向前掃描類體,並且(如果捕獲工作)提取它,*不*移動正則表達式的實際當前位置,所以它可以繼續匹配類名稱。 – chaos 2009-04-17 21:46:16

+0

你的模式並不完全匹配,但在未來展望中捕獲的想法是最終成功的。我一開始並沒有明白。 +1 – Rich 2009-04-20 15:53:16

1

這對正則表達式不是一個好問題。

在另一方面,你只需要幾個通行證的編寫基本的CSS解析器,肯定。

CSS語法就是[一些東西],[開大括號],[其他一些東西],畢竟[關閉大括號。

你找到的東西,這兩個塊,拆分的逗號的第一個和分號第二個,你就幾乎完成。

0

我需要對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; 

    }