簡體   English   中英

正則表達式IsMatch執行時間太長

[英]Regex IsMatch taking too long to execute

我在使用RegEx的.NET項目中遇到一個奇怪的問題。 請參閱下面的C#代碼:

const string PATTERN = @"^[a-zA-Z]([-\s\.a-zA-Z]*('(?!'))?[-\s\.a-zA-Z]*)*$";
const string VALUE = "Ingebrigtsen Myre (Øvre)";
System.Text.RegularExpressions.Regex regex = new System.Text.RegularExpressions.Regex(PATTERN);
if (!regex.IsMatch(VALUE)) // <--- Infinite loop here
     return string.Empty;
// Some other code

我使用此模式來驗證所有類型的名稱(拳頭名稱,姓氏,中間名等)。 值是一個參數,但我在上面作為常量提供了它,因為問題很少經常出現-僅帶有特殊符號:*,(,)等(對不起,但我沒有這些符號的完整列表) 。

您能幫我解決這個無限循環嗎? 謝謝你的幫助。

補充:這段代碼位於項目的最基本級別,我不想在那里進行任何重構-我只想快速解決此問題。

補充2:我確實知道從技術上講這不是循環-我的意思是“ regex.IsMatch(VALUE)”永無止境。 我等待了大約一個小時,它仍在執行。

非平凡的正則表達式: ^[a-zA-Z]([-\\s\\.a-zA-Z]*('(?!'))?[-\\s\\.a-zA-Z]*)*$最好在自由空間模式下用注釋編寫,如下所示:

Regex re_orig = new Regex(@"
    ^                 # Anchor to start of string.
    [a-zA-Z]          # First char must be letter.
    (                 # $1: Zero or more additional parts.
      [-\s\.a-zA-Z]*  # Zero or more valid name chars.
      (               # $2: optional quote.
        '             # Allow quote but only
        (?!')         # if not followed by quote.
      )?              # End $2: optional quote.
      [-\s\.a-zA-Z]*  # Zero or more valid name chars.
    )*                # End $1: Zero or more additional parts.
    $                 # Anchor to end of string.
    ",RegexOptions.IgnorePatternWhitespace);

用英語來說,此正則表達式本質上說: “匹配一個以字母[a-zA-Z]開頭,然后是零個或多個字母,空格,句點,連字符或單引號的字符串,但是每個單引號可能不會立即然后再加上一個單引號。”

請注意,您上面的正則表達式允許使用"ABC---...'... -.-.XYZ "名稱,例如: "ABC---...'... -.-.XYZ " ,可能不是您所需要的名稱。 它還允許多行輸入和以空格結尾的字符串。

上面的正則表達式的“無限循環”問題是,當將此正則表達式應用於行中包含兩個單引號的長無效輸入時,會發生災難性的回溯 這是一個等效模式,它匹配(但不匹配)完全相同的字符串,但不會發生災難性的回溯:

Regex re_fixed = new Regex(@"
    ^                # Anchor to start of string.
    [a-zA-Z]         # First char must be letter.
    [-\s.a-zA-Z]*    # Zero or more valid name chars.
    (?:              # Zero or more isolated single quotes.
      '              # Allow single quote but only
      (?!')          # if not followed by single quote.
      [-\s.a-zA-Z]*  # Zero or more valid name chars.
    )*               # Zero or more isolated single quotes.
    $                # Anchor to end of string.
    ",RegexOptions.IgnorePatternWhitespace);

在您的代碼上下文中,它是簡寫形式:

const string PATTERN = @"^[a-zA-Z][-\s.a-zA-Z]*(?:'(?!')[-\s.a-zA-Z]*)*$";

查看正則表達式的這一部分:

( [-\s\.a-zA-Z]* ('(?!'))? [-\s\.a-zA-Z]* )*$
^              ^         ^              ^  ^ 
|              |         |              |  |
|              |         |              |  This group repeats any number of times
|              |         |              charclass repeats any number of times
|              |         This group is optional
|              This character class also repeats any number of times
Outer group (repeated, as seen above)

這意味着只要您輸入的字符串包含不在字符類中的字符(例如示例中的方括號和非ASCII字母),前面的字符就會在許多排列中進行嘗試,排列的數目會隨着長度的增加而呈指數增加的字符串。

為了避免這種情況(並允許正則表達式更快失敗,請使用原子組

const string PATTERN = @"^[a-zA-Z](?>(?>[-\s\.a-zA-Z]*)(?>'(?!'))?(?>[-\s\.a-zA-Z])*)*$";

您在這里有“任意數量的任意數量”:

 ...[-\s\.a-zA-Z]*)*

並且由於您輸入的內容匹配,引擎會回溯嘗試對輸入進行划分的所有排列,並且嘗試次數會隨着輸入長度的增加而呈指數增長。

您可以簡單地通過添加“ +”來構成所有格修飾符來解決它,一旦使用所有格修飾符 ,就不會回溯找到其他組合:

const string PATTERN = @"^[a-zA-Z]([-\s\.a-zA-Z]*('(?!'))?[-\s\.a-zA-Z]*+)*$";
                                                                        ^-- added + here

您可以看到一個實時演示 (在rubular上),演示添加加號解決了循環問題,並且仍然匹配沒有奇數字符的輸入。

暫無
暫無

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

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