2014-01-24 22 views
2

我試圖清理HTML輸入字段。我想保留一些標籤,但不是全部標籤,因此在讀取元素值時不能只使用.text()。我在Safari中使用JavaScript中的正則表達式遇到了一些問題。這裏的代碼段的(我複製從另一個SO線程的答案正則表達式的該位):JavaScript替換()正則表達式太貪婪

aString.replace (/<\s*a.*href=\"(.*?)\".*>(.*?)<\/a>/gi, '$2 (Link->$1)') ; 

這裏是失敗的樣本輸入:

<a href="http://blar.pirates.net/black/ship.html">Go here please.</a></p><p class="p1"><a href="http://blar.pirates.net/black/ship.html">http://blar.pirates.net/black/ship.html</a></p> 

的想法是,在href將得到拉出並輸出爲純文本旁邊的文本將被鏈接。所以上面的輸出最終應該是這樣的:

Go here please (Link->http://blar.pirates.net/black/ship.html) 
http://blar.pirates.net/black/ship.html (Link->http://blar.pirates.net/black/ship.html) 

然而,正則表達式被抓一路下跌到第一比賽第二</a>標籤,所以我失去輸出的第一行。 (實際上,只要錨元素相鄰,它就會抓取到列表中最遠的那個元素。)輸入是一個長字符串,不會通過CR/LF或任何其他元素進行分割。

我已經使用非貪婪的標誌是這樣的(注意第二個問號)嘗試:

/<\s*a.*href=\"(.*?)\".*?>(.*?)<\/a>/ig 

但是,這似乎並沒有改變任何東西(至少不是在幾個測試儀/解析器我嘗試過,其中之一在這裏:http://refiddle.com)。也嘗試了/U標誌,但這沒有幫助(或這些解析器不認識它)。

有什麼建議嗎?的

href=\"(.*?)\"

基本上

+0

只是讓你知道,你的正則表達式將不會在防範'了'標籤足夠了,他們可以在href屬性中使用單引號或沒有引號。或者他們可以使用內聯onclick或其他事件處理程序。 – Markasoftware

+0

幸運的是,這不是一個公共系統,所以我不關心安全性。這只是試圖從粘貼到此字段的文本中刪除格式。 (這是一個內部評論系統 - 它們正在DB中的父記錄上輸入評論。) – Cronk

回答

3

裏有圖案的幾個錯誤和可能的改進:

/< 
\s* # not needed (browsers don't recognize "< a" as an "a" tag) 

a  # if you want to avoid a confusion between an "a" tag and the start 
     # of an "abbr" tag, you can add a word boundary or better, a "\s+" since 
     # there is at least one white character after. 

.  # The dot match all except newlines, if you have an "a" tag on several 
     # lines, your pattern will fail. Since Javascript doesn't have the 
     # "singleline" or "dotall" mode, you must replace it with `[\s\S]` that 
     # can match all characters (all that is a space + all that is not a space) 

*  # Quantifiers are greedy by default. ".*" will match all until the end of 
     # the line, "[\s\S]*" will match all until the end of the string! 
     # This will cause to the regex engine a lot of backtracking until the last 
     # "href" will be found (and it is not always the one you want) 

href= # You can add a word boundary before the "h" and put optional spaces around 
     # the equal sign to make your pattern more "waterproof": \bhref\s*=\s* 

\"  # Don't need to be escaped, as Markasoftware notices it, an attribute 
     # value is not always between double quotes. You can have single quotes or 
     # no quotes at all. (1) 
(.*?) 
\"  # same thing 
.*  # same thing: match all until the last > 
>(.*?)<\/a>/gi 

(1) - >關於報價和href屬性值:

爲了對付單,雙或沒有行情可以使用捕獲組和反向引用:

\bhref\s*=\s*(["']?)([^"'\s>]*)\1 

細節:

\bhref\s*=\s* 
(["']?)  # capture group 1: can contain a single, a double quote or nothing 
([^"'\s>]*) # capture group 2: all that is not a quote to stop before the possible 
      # closing quote, a space (urls don't have spaces, however javascript 
      # code can contain spaces) or a ">" to stop at the first space or 
      # before the end of the tag if quotes are not used. 
\1   # backreference to the capture group 1 

需要注意的是,你使用這個子模式添加捕獲組,並a標籤之間的內容現在是捕獲組3.想想您的替換字符串$2更改爲$3

在晴朗,你可以寫你的模式是這樣的:

aString.replace(/<a\s+[\s\S]*?\bhref\s*=\s*(["']?)([^"'\s>]*)\1[^>]*>([\s\S]*?)<\/a>/gi, 
       '$3 (Link->$1)'); 
+0

哇,好東西!我很欣賞徹底。我會查看這些內容並進行一些更改。 – Cronk

2

使用

href="[^"]+"

代替,這將抓住任何字符,直到它符合未來"

雖然它可能會更容易實現的東西像你不會有這種方式的降價語法擔心刪除錯誤的標籤,刪除所有內容,並在顯示文本時用他們的html標籤替換掉標記。

舉例來說,這樣您就可以通過只使用

[link text](http://linkurl.com)

和正則表達式做替換做一個鏈接將

var displayText = "This is just some text [and this is a link](http://example.com) and then more text"; 
var linkMarkdown = /\[([^\]]+)\]\(([^\)]+)\)/; 
displayText.replace(linkMarkdown,'<a href="$2">$1</a>'); 

或者使用已經取得圖書館,會做轉換。

+0

'href =「[^」] ++「'會比'href =」[^「] +」' ,因爲如果不匹配,它不會嘗試回溯到不可能的匹配(http://www.regular-expressions.info/possessive.html獲取信息)。但Markasoftware有一點,這個正則表達式可能沒有足夠的保護。 – Robin

+1

@Robin:Javascript正則表達式沒有佔有量詞,也沒有原子組。然而,你可以用這個技巧來模擬一個原子組(也就是'(?> a +) a ++'),因爲前瞻是原子的 –

+0

我會給出建議的改變一個嘗試,我認爲markdown對於這個用法有點多,這是一個跟蹤評論的內部系統;我只需要去掉大部分來自可能複製/粘貼的人的格式化HTML我試圖很好地提取自己可能複製的鏈接的網址 – Cronk

1

謝謝大家的建議;它幫助了我很多,並且有很多想法來改進它。

但我想我找到了原始正則表達式失敗的具體原因。卡西米爾的回答觸及了它,但直到我遇到這種修復之前,我才瞭解它。

我一直在找錯了地方的問題,在這裏:

/<\s*a.*href=\"(.*?)\".*>(.*?)<\/a>/gi 
        ^

我能夠通過a.*hre區域之後插入一個問號來解決我原來的查詢,如:

/<\s*a.*?href=\"(.*?)\".*>(.*?)<\/a>/gi 
     ^

我打算在此處使用其他建議來進一步改進我的聲明。

- Visual C