Добавление отдельного символа к моему RegEx.NET заставляет это зависать

Вот входные данные:

                                *** INVOICE ***                                

                              THE BIKE SHOP                              
                      1 NEW ROAD, TOWNVILLE,                       
                          SOMEWHERE, UK, AB1 2CD                          
                        TEL 01234-567890  

 To: COUNTER SALE                                   No:  243529 Page: 1

                                                    Date: 04/06/10 12:00

                                                    Ref:    Aiden   

 Cust No: 010000                 

Вот regex, который работает (Опции: одна строка, ignorewhitespace, скомпилированный) - это сразу соответствует, и группы правильно заполняются:

\W+INVOICE\W+
(?<shopAddr>.*?)\W+
To:\W+(?<custAddr>.*?)\W+
No:\W+(?<invNo>\d+).*?
Date:\W+(?<invDate>[0-9/ :]+)\W+
Ref:\W+(?<ref>[\w ]*?)\W+
Cust 

Как только я добавляю, что 'N' из Cust No в короля, анализируя вход зависает навсегда:

\W+INVOICE\W+
(?<shopAddr>.*?)\W+
To:\W+(?<custAddr>.*?)\W+
No:\W+(?<invNo>\d+).*?
Date:\W+(?<invDate>[0-9/ :]+)\W+
Ref:\W+(?<ref>[\w ]*?)\W+
Cust N

Если я добавляю что-то как "любой символ":

\W+INVOICE\W+
(?<shopAddr>.*?)\W+
To:\W+(?<custAddr>.*?)\W+
No:\W+(?<invNo>\d+).*?
Date:\W+(?<invDate>[0-9/ :]+)\W+
Ref:\W+(?<ref>[\w ]*?)\W+
Cust .

Это работает, но как только я добавляю фиксированный символ, король зависает снова:

\W+INVOICE\W+
(?<shopAddr>.*?)\W+
To:\W+(?<custAddr>.*?)\W+
No:\W+(?<invNo>\d+).*?
Date:\W+(?<invDate>[0-9/ :]+)\W+
Ref:\W+(?<ref>[\w ]*?)\W+
Cust ..:

Кто-либо может советовать, почему, добавляя что-то таким образом тривиальное заставило бы это падать? Я могу позволить некоторой трассировке следить за действием соответствия, чтобы видеть, застревает ли это в катастрофическом отслеживании в обратном порядке?

5
задан Matt 4 June 2010 в 13:20
поделиться

2 ответа

С помощью RegexOptions.IgnorePatternWhitespace вы указываете движку игнорировать пробелы в шаблоне. Таким образом, когда вы пишете Cust No в шаблоне, на самом деле это означает CustNo, что не соответствует введенным данным. Это и есть причина проблемы.

Из документации:

По умолчанию пробел в шаблоне регулярного выражения является значимым; это заставляет механизм регулярного выражения соответствовать символу пробела во входной строке. [...]

Опция RegexOptions.IgnorePatternWhitespace, или x inline, изменяет это поведение по умолчанию следующим образом:

  • Незаписанный пробел в шаблоне регулярного выражения игнорируется. Чтобы быть частью шаблона регулярного выражения, символы пробела должны быть экранированы (например, как \s или "\ ").

Поэтому вместо Cust No в режиме IgnorePatternWhitespace вы должны написать Cust\ No, потому что иначе это будет интерпретировано как CustNo.

8
ответ дан 13 December 2019 в 22:02
поделиться

polygenelubricants уже объясняли, почему ваше регулярное выражение не удалось . Причина зависания в том, что вы столкнулись с катастрофическим возвратом . В вашем регулярном выражении много частей, которые могут соответствовать одному и тому же тексту разными способами. Если общее совпадение не удается, механизм регулярных выражений будет пробовать все возможные перестановки, пока не исчерпает их все или не прервется с переполнением стека.

E. грамм. в To: \ W + (? . *?) \ W + . *? с радостью будет соответствовать тем же символам, что и \ W , и поскольку вы используете Singleline , . *? также будет переходить в часть No: ... входного текста и дальше и дальше. В вашем примере я тестировал в RegexBuddy, что произойдет, если вы добавите «N» после «Cust» - механизм регулярных выражений прерывается после 1 000 000 шагов.

Чтобы избежать этого, вам нужно сделать регулярное выражение более конкретным или (в данном случае это может быть лучший вариант) не допускать возврата механизма регулярных выражений, заключая части, которые уже совпали в " атомных группах ":

(?>\W+INVOICE\W+)
(?>(?<shopAddr>.*?)\W+To:)
(?>\W+(?<custAddr>.*?)\W+No:)
(?>\W+(?<invNo>\d+).*?Date:)
(?>\W+(?<invDate>[0-9/\ :]+)\W+Ref:)
(?>\W+(?<ref>[\w\ ]*?)\W+Cust)

Это позволяет регулярному выражению выходить из строя намного быстрее, если входные данные и регулярное выражение не подходят друг к другу.

2
ответ дан 13 December 2019 в 22:02
поделиться
Другие вопросы по тегам:

Похожие вопросы: