2012-05-10 2 views
1

У меня есть регулярное выражение, чтобы проверить, содержит ли ячейка CSV правильного путь к файлу:RegExp бесконечный цикл только в perl, почему?

EDIT CSV-список путей файлов, которые еще не существует при запуске сценария (я не могу использовать -e), и путь_к_файл может включать в себя * или% variable% или {$ variable}.

my $FILENAME_REGEXP = '^(|"|""")(?:[a-zA-Z]:[\\\/])?[\\\/]{0,2}(?:(?:[\w\s\.\*-]+|\{\$\w+}|%\w+%)[\\\/]{0,2})*\1$'; 

Поскольку клетки CSV иногда содержит обертки двойных кавычек, а иногда и само имя файла должен быть завернуто в двойных кавычках, я сделал эту группировку (| «|» «») ... \ 1

Затем с помощью этой функции:

sub ValidateUNCPath{ 
    my $input = shift; 
    if ($input !~ /$FILENAME_REGEXP/){ 
     return; 
    } 
    else{ 
     return "This is a Valid File Path."; 
    } 

} 

Я пытаюсь проверить, если эта фраза соответствует моему регулярному выражению (Оно не должно совпадать):

"""c:\my\dir\lord" 

, но мой дорогой Perl попадает в бесконечный цикл, когда:

ValidateUNCPath('"""c:\my\dir\lord"'); 

EDIT на самом деле это петли на этом:

ValidateUNCPath('"""\aaaaaaaaa\bbbbbbb\ccccccc\Netwxn00.map"'); 

Я убедился в http://regexpal.com, что мое регулярное выражение правильно улавливает те несимметричные " «...» обертывание двойных кавычек, но Perl получил свой собственный ум :(

Я даже попробовал флаги/g и/o в

/$FILENAME_REGEXP/go 

но он все еще висит. Что мне не хватает?

+2

Там нет коды вы выложили что может вызвать бесконечный цикл. – TLP

+0

вместо возврата; попробуйте вернуться ""; –

+1

Синтаксис 'if (...) return; else return; 'приведет к синтаксической ошибке в perl ... почему бы вам не вставить ваш * настоящий * код, включая цикл, который вы используете, тогда мы сможем вам помочь. – TLP

ответ

3

Во-первых, ничего, что вы опубликовали, может привести к бесконечному циклу, поэтому, если вы получаете его, его не от этой части кода.

Когда я пытаюсь вашу подпрограмму, он возвращает истину для всех видов струн, которые далеки от поиска путей, как, например:

..... 
This is a Valid File Path. 
.*.* 
This is a Valid File Path. 
- 
This is a Valid File Path. 

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

^(|"|""")     # can match the empty string 
(?:[a-zA-Z]:[\\\/])?  # same, matches 0-1 times 
[\\\/]{0,2}    # same, matches 0-2 times 
(?:(?:[\w\s\.\*-]+|\{\$\w+}|%\w+%)[\\\/]?)+\1$ # only this is not optional 

Поскольку только последняя часть на самом деле должна соответствовать что-нибудь, вы позволяете все виды строк, в основном в первом классе символов: [\w\s\.\*-]

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

Почему бы вам не просто удалить цитаты?Кроме того, если этот путь существует в вашей системе, существует гораздо более простой способ проверить, если он действительно: -e $path

+0

Все ваши тесты имеют вполне допустимые относительные пути к файлам, поэтому они не показывают, что регулярное выражение нарушено. –

+0

@RobKennedy Я не думаю, что любая строка, состоящая из '[\ w \ s \. \ * -] +', является допустимым путем. – TLP

+0

Каждый из ваших тестов подходит для этого регулярного выражения, и каждый из ваших тестов является допустимым относительным путем. –

1

Update

Edit: Из проб и ошибок, ниже группировка Подвыражение [\w\s.*-]+ является вызывая проблему BACKTRACK

(?: 
     (?: 
      [\w\s.*-]+ 
      | \{\$\w+\} 
      | %\w+% 
     ) 
     [\\\/]? 
    )+ 

Fix # 1, раскатали метод

' 
^ 
    (       # Nothing 
     |"      # Or, " 
     |"""      # Or, """ 
    ) 
         # Here to end, there is no provision for quotes (") 
    (?:    # If there are no balanced quotes, this will fail !! 
     [a-zA-Z] 
     : 
     [\\\/] 
    )? 
    [\\\/]{0,2} 

    (?: 
     [\w\s.*-] 
     | \{\$\w+\} 
     | %\w+% 
    )+ 
    (?: 
     [\\\/] 
     (?: 
      [\w\s.*-] 
      | \{\$\w+\} 
      | %\w+% 
     )+ 
    )* 
    [\\\/]? 
    \1 
$ 
' 

Fix # 2, независимое подвыражение

' 
^ 
    (       # Nothing 
     |"      # Or, " 
     |"""      # Or, """ 
    ) 
         # Here to end, there is no provision for quotes (") 
    (?:    # If there are no balanced quotes, this will fail !! 
     [a-zA-Z] 
     : 
     [\\\/] 
    )? 
    [\\\/]{0,2} 

    (?> 
     (?: 
      (?: 
       [\w\s.*-]+ 
      | \{\$\w+\} 
      | %\w+% 
      ) 
      [\\\/]? 
     )+ 
    ) 
    \1 
$ 
' 

Fix # 3, удалите + квантор (или добавить +?)

' 
^ 
    (       # Nothing 
     |"      # Or, " 
     |"""      # Or, """ 
    ) 
         # Here to end, there is no provision for quotes (") 
    (?:    # If there are no balanced quotes, this will fail !! 
     [a-zA-Z] 
     : 
     [\\\/] 
    )? 
    [\\\/]{0,2} 

    (?: 
     (?: 
      [\w\s.*-] 
      | \{\$\w+\} 
      | %\w+% 
     ) 
     [\\\/]? 
    )+ 
    \1 
$ 
' 
+0

Это именно то, что я хочу - потерпеть неудачу на несимметричных котировках. Но проблема в том, что для вычисления регулярного выражения требуется perl для perl. Попробуйте эту фразу - мой perl зависает на ней: ** ValidateUNCPath ('"" "\ aaaaaaaaa \ bbbbbbb \ ccccccc \ Netwxn00.map"'); ** –

+0

@Noam Manos - Хорошо, я вижу проблему. Добавлено обновление с исправлением. – sln

+0

Спасибо! вы нашли причину цикла, хотя я не понимаю, почему RegExPal.com работал, но Perl повешен раньше ... И что делает?> в fix # 2 do? –

1

Если регулярное выражение двигатель был на ï ве,

('y') x 20 =~ /^.*.*.*.*.*x/ 

займет очень много времени на провал, так как он должен попробовать

20 * 20 * 20 * 20 * 20 = 3,200,000 possible matches. 

Ваш шаблон имеет аналогичную структуру, то есть он имеет множество компонентов, соответствующих широкому диапазону подстрок вашего ввода.

Теперь, регулярный двигатель Perl высоко оптимизирован и далеко от na ï ve. В приведенном выше шаблоне он начнется с поиска x и выйдет очень быстро. К сожалению, он не может или не может так же оптимизировать ваш шаблон.

Ваши шаблоны - полный беспорядок. Я не собираюсь даже пытаться угадать, что это такое. Вы обнаружите, что эта проблема решит себя, как только вы перейдете к правильному шаблону.

0

Благодаря Sln это мое фиксированное регулярное выражение:

my $FILENAME_REGEXP = '^(|"|""")(?:[a-zA-Z]:[\\\/])?[\\\/]{0,2}(?:(?:[\w\s.-]++|\{\$\w+\}|%\w+%)[\\\/]{0,2})*\*?[\w.-]*\1$'; 

(я также запрещен * символ в каталогах, и допускается только одного * в (последнем) файле)

+0

Вы должны иметь возможность значительно ускорить это, используя'^(| "|" "")?? (?: [A-Za-Z]: [\\\ /]) [\\\ /] {0,2} (: (: [\ ш \ s .-] ++ | \ {\ $ \ w + \} |% \ w +%) [\\\ /] {0,2}) * \ *? [\ w .-] * \ 1 $ ''Это слияние перекрытие и добавление квантификатора Possesive '++' (то же самое, что и атомарная '(?>)' группировка), из-за которой вложенное квантование возвращается в старый regex. В наименьшем смысле вместо '(?: (?: [ \ w \ s .-])) * ',' (?: (?: [\ w \ s .-] ++)) * 'на FAIL, не будет выполняться немедленно, а не возвращаться и потреблять быстро, а не 1 символ в – sln

+0

Спасибо @sln - на моем локальном Perl он отлично работает сейчас! (Regexpal.com не принимает его, однако ....) - Я изменяю свой последний ответ как вы предложили. –

Смежные вопросы