簡體   English   中英

是否需要嵌套正則表達式?

[英]Is nesting regexes ever necessary?

我想從看起來與此相似的HTML中提取兩個數字10和11,只是它比我在此處顯示的噪聲更大:

<div a>
<noise=53>
<item=10>
<item=11>
</div>
<div b>
<item=20>
<noise=52>
<item=21>
</div>

我已經弄清楚如何通過使用兩個正則表達式來做到這一點:第一次使用

(?s)(?<=<div a>).*?(?=</div>)

在“ div a”部分中獲取內容,然后使用

(?s)(?<=<item=)[0-9]*

在結果上得到我想要的數字。 但是我無法弄清楚如何僅使用一個正則表達式。 我有一個猜測,如果只有Java讓我將* s放到后面,而Java沒有(我隱約地明白為什么不這樣做),那我該怎么辦。 是否可以僅使用一個正則表達式來執行此操作,或者我應該滿足兩個條件?

我認為您不能陷入困境。 但是請注意,最好使用XML或HTML解析器來分解HTML。 如果HTML是格式良好的XHTML,則可以使用XML解析器。 否則請查看http://java-source.net/open-source/html-parsers

我不確定您嵌套正則表達式的意思。 通常采用這種方法的方法是一次像詞法分析器一樣仔細地一次完成操作。 這樣,您不必嘗試將所有內容構建為一個模式。

除了使用Matcher.matches() ,您還可以使用Matcher.lookingat() ,該方法從當前起點開始尋找內容。 這樣,您可以從同一位置測試一堆。

一種類似的策略涉及使用Matcher.find()的單參數形式,您在其中提供起始字符位置作為參數。

一個相關的功能是\\G錨,它是一個零寬度的斷言,使搜索從該相同字符串的最后一個匹配項停止的地方開始。 這樣可以為您節省一些簿記。

通過結合使用find(N)lookingat()方法(加上start() )的明智使用,也許結合\\G斷言,您可以構建自己的靈活性和復雜性的處理算法,這比僅使用單個正則表達式所能實現的要復雜。

與嘗試在一個龐大的正則表達式中進行所有操作相比,使用結構化邏輯和常規Java管理您的正則表達式要容易得多。 這樣,開發,調試和單元測試也要容易得多。 正則表達式最適合處理字符串,而不是嘗試在其中編碼整個解析算法。

另外,在Java中,您還是不能真正做到這一點,因為該模式中不支持遞歸。 也許也一樣,因為它鼓勵您將控制結構放到外部語言中,因為您不能總是將所有需要的內容放到內部語言中。

import java.util.regex.*;

public class Test
{
  public static void main(String[] args)
  {
    String s = "<div x><item=02><noise=99><item=05></div>\n" + 
        "<div a><noise=53><item=10><item=11><noise=55><item=12></div>\n" + 
        "<item=99>\n" + 
        "<div b><item=20><noise=52><item=21></div>";
    System.out.println(s);
    System.out.println();
    Pattern p = Pattern.compile(
        "(?:<div a>|\\G)(?:[^<]++|<(?!(?:item|/?div)\\b))*+<item=(\\d+)");
    Matcher m = p.matcher(s);
    while (m.find())
    {
      System.out.println(m.group(1));
    }
  }
}

輸出:

<div x><item=02><noise=99><item=05></div>
<div a><noise=53><item=10><item=11><noise=55><item=12></div>
<item=99>
<div b><item=20><noise=52><item=21></div>

10
11
12

分解,我們有:

  • (?:<div a>|\\\\G)\\G匹配上次匹配結束的地方,如果沒有先前匹配,則匹配文本的開頭。 下一部分的前瞻可防止它在開始時匹配,因此第一個匹配從<div a>

  • (?:[^<]++|<(?!(?:item|/?div)\\\\b))*+ :這部分消耗當前匹配位置和下一個<item=N>標記之間的任何內容。 如果不是<item<div</div序列的開頭,它將吞噬除<<以外的所有字符。 (后兩個確保所有<item=N>匹配項都包含在同一個div元素中;此外, <div是阻止\\G在文本開頭進行匹配的原因,而</div阻止div元素之間的匹配,例如在示例中為<item=99> 。)

  • 最后, <item=(\\\\d+)匹配item標記並捕獲您想要的編號。

我認為Sed實用程序比使用正則表達式編程提取文本數據更有用。 嘗試在Sed中使用以下腳本(帶有-n選項)。

/<div \w>/,/<\/div>/ {
    s/.*item=\([0-9]\+\).*/\1/p
}

如果它是真正的HTML,則可以將其轉換為XML,例如通過HTMLTidy或NekoHTML,然后應在其上使用XPath表達式。

甚至不要嘗試,您需要一個解析器,許多解析器都可用。

暫無
暫無

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

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