簡體   English   中英

單個開始標記內的 HTML 屬性的正則表達式(無子元素)

[英]regex for HTML attributes inside a single opening tag (no child elements)

旁白:這個問題不是RegEx match open tags 除了 XHTML self-contained tags的重復,其答案是“不要對 HTML 使用正則表達式,因為你不能”。 這個答案不是這個問題的解決方案 這個問題需要一個正則表達式解決方案,我找到了解決方案並將其發布在下面。

這是我想在不使用 DOM API的情況下從中獲取屬性的 HTML 文本:

     <div
      blah lorem
      foo-bar
            multi-line="
             foo
              bar
            "
          df"234   Yeah,that-is-an-attribute-too!_And-so-is-this-one!
                bar=" asdf"
                bar=  zxcv 
            foo=asdf
                aa=df-bar=()
                a-b=df-b"ar=()
                ac=df"-bar=()
                ad=df-bar=()
     ></div>
             

這是我到目前為止的正則表達式:

/(?:\s(?:[^'"/\s><]+?)[\s/>])|(?:\S+(?:\s*=\s*(?:(?:(['"])[\s\S]*?\1|([^\s>]+))|(?:[^'"\s>]+))))/g

它幾乎可以工作。 樣本:

 const re = /(?:\s(?:[^'"/\s><]+?)[\s/>])|(?:\S+(?:\s*=\s*(?:(?:(['"])[\s\S]*?\1|([^\s>]+))|(?:[^'"\s>]+))))/g const html = ` <div blah lorem foo-bar multi-line=" foo bar " df"234 Yeah,that-is-an-attribute-too!_And-so-is-this-one! bar=" asdf" bar= zxcv foo=asdf aa=df-bar=() ab=df-b"ar=() ac=df"-bar=() ad=df-bar=() ></div> ` const result = html.match(re).map(s => s.trim()) console.log(result)

在這里現場探索:
https://regexr.com/6p82ghttps://regex101.com/r/1zOh1S/1

它沒有拾取lorem布爾屬性,並且bar= zxcv屬性被錯誤地檢測為兩個屬性。

如果刪除第一部分(?:\s(?:[^'"/\s><]+?)[\s/>])| ,那么它幾乎也可以工作,它會選擇除布爾值之外的所有屬性屬性(不帶= ):
https://regexr.com/6p82jhttps://regex101.com/r/iLOVpv/1

我們如何才能正確選擇所有屬性?

  • 將第一個[^'"/\s><]替換為[^/\s><=]以避免它拾取帶有值的屬性,並且還拾取名稱中帶有引號的布爾屬性,例如foo"barfoo'bar (這些是完全有效的)
  • 用積極的前瞻包裝[\s/>]以將其從實際匹配中排除( (?=[\s/>]) ),這樣我們就解決了背靠背布爾屬性(fe lorem )不存在的問題包括
  • \S+替換 \ \S+? 這樣當我們添加捕獲組時,像ad=df-bar=()這樣的屬性將被檢測為具有值df-bar=()的名稱ad而不是具有值()的名稱ad=df-bar
  • 刪除接近末尾的|([^'"\s>]+) ,它不做任何事情,並允許我們刪除一個非捕獲組包裝器(保留那些用於表達意圖)
  • 最后更新組,以便我們可以捕獲所需的值

最終的正則表達式是:

/(?:\s([^/\s><=]+?)(?=[\s/>]))|(?:(\S+?)(?:\s*=\s*(?:(['"])([\s\S]*?)\3|([^\s>]+))))/g

樣本:

 const re = /(?:\s([^/\s><=]+?)(?=[\s/>]))|(?:(\S+?)(?:\s*=\s*(?:(['"])([\s\S]*?)\3|([^\s>]+))))/g // ^ capture group 1: boolean attribute name (attributes without values) // ^ capture group 2: non-boolean attribute name // ^ capture group 4: non-boolean attribute value with quotes // ^ capture group 5: non-boolean attribute value without quotes const html = ` <div blah lorem foo-bar multi-line=" foo bar " df"234 Yeah,that-is-an-attribute-too!_And-so-is-this-one! bar=" asdf" bar= zxcv foo=asdf aa=df-bar=() ab=df-b"ar=() ac=df"-bar=() ad=df-bar=() ></div> ` const result = Array.from(html.matchAll(re)) for (let i = 0, l = result.length; i < l; i += 1) { const match = result[i] console.log('name: "' + (match[1] || match[2]) + '", value: "' + (match[4] || match[5] || "") + '"') }

現場探索: https ://regexr.com/6p8p0

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM