Re: [請益] 請問重複attr合併的正規法要如何寫?

作者: banana2014 (香蕉共和國)   2017-07-23 14:13:01
※ 引述《pk9058 (WhenSunTea)》之銘言:
: 如標題
: regex:/(style[=]["](.*?)["]{2})/ig
: HTML內容:
: <div id="test" style="color:#FFF;" class="title_block" style="background:#000;" title="Hello">
: <span style="font-size:18pt;">標題</span>
: </div>
: 在 regexr.com 測試發現他會連同 h2 的style也包含...
: 麻煩版上的大大幫小弟解惑,謝謝
不曉得您的意思是不是要找同一個元素裡的所有style標籤
如果是,那有兩種做法:
第一種作法比較簡單
可以單純只用一條Regex來找出「最後那個元素」的所有style標籤
而且所有程式語言都通
Regex的pattern如下:
/(style=)('|\")[^'\"]*\2(?!(.|\n)*>(.|\n)*\1('|\")[^'\"]*\5)/gi
如下的程式碼會匹配到紅色字:
<div id="test" style="color:#FFF;" class="title_block" style="background:#000;" title="Hello" style="font-size:16px;">
<input style="font-size:18pt;" disabled style="color:red;" name="inp" style="text-align:left;">
<span style="color:#F00;" style="font-family:arial;">ABC</span>
</div>
<div style="text-decoration:none;" id="test2" style="color:blue">333</div>
我來說明一下這條pattern:
第一個桃紅色部分的「(style=)」意思是匹配「style=」這個字串,這沒什麼學問。
第二個黃色部分的「('|\")[^'\"]*\2」意思是先匹配單引號(')或者雙引號(")1次,然後後面可能有一個或多個不是單引號或雙引號的字元,但也有可能沒接,然後再接跟第2個括號裡匹配的相同字元 (也就是如果你第一次輸入雙引號,這邊就必須也是雙引號,反之單引號亦然)
最後綠色部分的「(?!(.|\n)*>(.|\n)*\1('|\")[^'\"]*\5)」意思是這整個「style="..."」標籤的後面不能有大於符號(>)然後又接著出現「style="..."」或「style='...'」的字樣。
所以只要是最後一個元素的style標籤就通通可以match得到。
第二種就比較複雜麻煩了,必須要配合程式來做才行,而且不見得所有瀏覽器都支援這種方法:
第二種就可以像你所說的匹配「第一個元素」的所有style標籤
如果您是用Javascript寫
Regex的pattern如下:
/[^>]*?(style=)('|\")[^'\"]*\2(?=[^>]*>[^>]*)/gyi
這裡我們用到了新的modifier:「y」(在舊瀏覽器,如IE可能不支援)
我來說明一下這個「y」好了
「y」是取「Sticky」的「y」來作為這個modifier的名稱
意思是:「只允許從開頭開始的連續匹配(如果「g」被設定則會連續),連續處是從上一個匹配的字的結尾處開始」
例如:
/a/gy
這裡我們只可以匹配所有連續且從開頭開始的「a」
所以「aaassaaaa」只匹配到前三個「a」,後面的「a」則完全都匹配不到
另外像「mmmaaassaaaa」則所有的「a」都匹配不到。
回來上面的Regex pattern,
這行pattern的意思就是:如果「style="..."」或「style='...'」的前面都沒有任何大於符號(>) ([^>]*?),且後面又有出現大於符號(>) ((?=[^>]*>[^>]*)),然後又從開頭連續 (y modifier、g modifier),那麼就匹配
所以像下面這段原始碼會匹配到有底色的字:
<div id="test" style="color:#FFF;" class="title_block" style="background:#000;" title="Hello" style="font-size:16px;" alt="test" style="text-shadow:none;">
<span style="font-size:18pt;" title="test1" style="text-decoration:none;" id="test1" style="font-family:arial;">ABC</span>
<span style="color:blue;" style="font-weight:bold;">Hello!</span>
</div>
<div style="position:absolute;" class="test2" style="top:0;left:0;"></div>
但是這並不是我們要的結果,
我們只想要像「style="..."」這樣的標籤
所以就必須要用Javascript程式去擷取字串了。
程式如下:
var str = "(原始碼...)";
var res = str.match(/[^>]*?(style=)('|\")[^'\"]*\2(?=[^>]*>[^>]*)/gyi);
var result = res.map(function(s){ return s.substr(s.indexOf("style=")); });
最後得到的陣列result就是我們想要的結果
◎ 其中這裡的map就是對某一陣列一一做函數的處理。
如果您用第二種方法是用PHP寫的,那麼就把「y」改成「A」即可
「A」與「y」功能雷同,在此不再贅述。
以上。
作者: CauseSam (天翼)   2017-07-24 08:21:00
高手!
作者: maiico (ming)   2017-07-24 10:45:00
很詳細
作者: ian90911 (xopowo)   2017-07-24 10:48:00
推優文
作者: pk9058 (WhenSunTea)   2017-07-24 22:44:00
感謝大大的熱心回復 :)目前小弟的寫法是先用下面這段regex來取得attr groupstyle\s*=\s*['"]?([^'"]+)['"]?/ig之後將它刪除,然後重建新的 style這是我自己寫的正規表示法,如有錯誤希望大大可以指正小弟https://codepen.io/anon/pen/oeNdRZ小弟熟讀您的文章後又學到新的一課,感謝大大的細心教導

Links booklink

Contact Us: admin [ a t ] ucptt.com