Определение допустимости URI с помощью регулярного выражения Perl - PullRequest
3 голосов
/ 23 июня 2011

Для приложения, которое я разрабатываю, мне нужен Perl-скрипт, который просматривает массивный CSV-файл и гарантирует, что каждая строка содержит действительный URI. Ранее я уже задавал вопрос о разборе файла CSV, и я начал использовать Text::CSV, чтобы сделать мою жизнь намного проще. Теперь у меня есть проблема с гарантией, что URI действителен.

Из-за характера моего заявления URI не обязательно должны принимать полную форму

protocol://username:password@domain.extension/request?vars=values

Скорее меня интересует только часть запроса об этом. Для обычного веб-сайта это будет что-нибудь после .com, .edu и т. Д.

В настоящее время у меня есть следующий скрипт Perl:

if($_ !~ /^(?:[a-z0-9-._~!$&'()*+,;=:/?@]|%[0-9A-F]{2})*$/i){
    print "Invalid URL format";
    exit;
} else {
    /* stuff */
}

Регулярное выражение должно быть довольно простым. Запрос может содержать один из небольшого набора символов ([a-z0-9-._~!$&'()*+,;=:/?@]) или может содержать знак процента (%), за которым следуют две шестнадцатеричные цифры. Любой из этих шаблонов может повторяться бесконечно.

Когда я запускаю этот скрипт, я получаю следующую ошибку:

Number found where operator expected at ./301rules.pl line 58, near "%[0"
        (Missing operator before 0?)
Bareword found where operator expected at ./301rules.pl line 58, near "9A"
        (Missing operator before A?)
Bareword found where operator expected at ./301rules.pl line 58, near "$/i"
        (Missing operator before i?)
syntax error at ./301rules.pl line 58, near "%[0"

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

if($_ !~ /^(?:[a-z0-9\-\.\_\~\!\$\&\'\(\)\*\+\,\;\=\:\/\?\@]|%[0-9A-F]{2})*$/i){

Однако, когда я сделал это, он просто позволил каждой строке пройти тест, даже строки, которые, как я знал, являются недействительными, такие как te%st или é

Так кто-нибудь имеет опыт работы с Perl regex и знает, что мне нужно убежать, а что мне не следует убегать? С 19 различными символами мне не хочется пробовать все 2 ^ 19 = 524288 возможностей.

РЕДАКТИРОВАТЬ - голосование закрыть. Я обнаружил, что проблема действительно существовала непосредственно над этим циклом, хотя я еще не совсем понимаю, почему.

У меня было:

if( $_ == "" ){
    next;
}
/* regex conditional from above */

По какой-то причине он продолжал оценивать как true и переходить к следующей итерации, несмотря на то, что в $_ явно хранятся данные. Я выясню, почему это так, но сейчас регулярное выражение работает нормально, когда все вышло.

Ответы [ 3 ]

5 голосов
/ 23 июня 2011

В документации на URI модуль я обнаружил следующее:

ПАРСИНГ URI С REGEXP

В качестве альтернативы этому модулю следующий (официальный) регулярный Выражение может быть использовано для декодирования URI:

    my($scheme, $authority, $path,
    $query, $fragment) =   $uri =~
    m|(?:([^:/?#]+):)?(?://([^/?#]*))?([^?#]*)(?:\?([^#]*))?(?:#(.*))?|;

Модуль URI :: Split предоставляет Функция uri_split () в качестве удобочитаемой альтернативы.

Но я думаю, Regexp :: Common :: URI , вероятно, является идеальным решением для проверки синтаксиса HTTP URI.

use Regexp::Common qw /URI/;
while (<>) {
    /$RE{URI}{HTTP}/  and  print "Contains an HTTP URI.\n";
}

Все, что написано Дамианом и поддерживается Абигайль, должно быть вдохновленным, великим, сумасшедшим или всем вышеперечисленным. (И я имею в виду это с максимально возможным уважением).

2 голосов
/ 23 июня 2011

Я не знаю, как вы добрались до своего первого регулярного выражения, но я постараюсь помочь вам исправить это.Вам нужно только экранировать символы, которые имеют особое значение в регулярном выражении - из вашего регулярного выражения они: -,., $, (,), *, /, Поэтому регулярное выражение должно выглядеть так:* Я точно не знаю, чего ?: пытается достичь там, но ваш первый класс символов, который просто следует за ним (выражение между первым []), не имеет никаких множителей - возможно, за ним должно следовать*, + или?Кроме того, знак |, который, я думаю, предназначен для обозначения or между вашим первым классом символов и вторым классом символов, перед которым стоит % - как это выглядит сейчас, он находится между первым классом символов и% только знак.Это, вероятно, должно быть как |(%[0-9A-F]{2}))*$

0 голосов
/ 23 июня 2011

Вы должны использовать регулярное выражение rfc для проверки КАЖДОГО возможных символов.Посмотрите на это

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...