簡體   English   中英

Java正則表達式匹配開始/結束標簽導致堆棧溢出

[英]Java regex to match start/end tags causes stack overflow

Java Pattern類的標准實現使用遞歸來實現多種形式的正則表達式(例如,某些運算符、交替)。

這種方法會導致超過(相對較小)長度的輸入字符串出現堆棧溢出問題,長度甚至可能不超過 1,000 個字符,具體取決於所涉及的正則表達式。

一個典型的例子是以下正則表達式使用交替從周圍的 XML 字符串中提取可能的多行元素(名為Data ),該字符串已經提供:

<Data>(?<data>(?:.|\r|\n)+?)</Data>

上述正則表達式與Matcher.find()方法一起使用以讀取“數據”捕獲組並按預期工作,直到提供的輸入字符串的長度超過 1,200 個字符左右,在這種情況下會導致堆棧溢出。

可以重寫上面的正則表達式以避免堆棧溢出問題嗎?

有關堆棧溢出問題起源的更多詳細信息:

有時正則表達式Pattern類會拋出StackOverflowError 這是已知錯誤 #5050507的表現,自 Java 1.4 以來,該錯誤一直存在於java.util.regex包中。 該錯誤將繼續存在,因為它處於“無法修復”狀態。 出現此錯誤是因為Pattern類將正則表達式編譯成一個小程序,然后執行該程序以查找匹配項。 這個程序是遞歸使用的,有時當遞歸調用太多時會出現這個錯誤。 有關更多詳細信息,請參閱錯誤描述 似乎它主要是由使用交替觸發的。

您的正則表達式(有交替)匹配兩個標簽之間的任何 1+ 個字符。

您可以使用帶有Pattern.DOTALL修飾符(或等效的嵌入標志(?s) )的惰性點匹配模式,這將使. 也匹配換行符:

(?s)<Data>(?<data>.+?)</Data>

看到這個正則表達式演示

然而,在大量輸入的情況下,惰性點匹配模式仍然會消耗大量內存。 最好的方法是使用unroll-the-loop 方法

<Data>(?<data>[^<]*(?:<(?!/?Data>)[^<]*)*)</Data>

查看正則表達式演示

詳情

  • <Data> - 文字文本<Data>
  • (?<data> - 捕獲組“數據”的開始
    • [^<]* - 除<之外的零個或多個字符
    • (?:<(?!/?Data>)[^<]*)* - 0 個或多個序列:
      • <(?!/?Data>) - 一個<后面沒有跟Data>/Data>
      • [^<]* - 除<之外的零個或多個字符
  • ) - “數據”組的結尾
  • </Data> - 結束分隔符

暫無
暫無

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

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