Получить вторую строку URI с помощью регулярного выражения Perl - PullRequest
2 голосов
/ 14 июня 2019

Мне нужно получить вторую часть URI, возможные URI:

/api/application/v1/method
/web/application/v1/method

Я могу получить "application" используя:

([^\/api]\w*)

и

([^\/web]\w*)

Но я знаю, что это не лучший подход, какой будет хороший путь?

Спасибо!

Редактировать: спасибо всем за ввод, цель состояла в том, чтобы установить второй раздел URI в заголовок в apache с правилами перезаписи

Ответы [ 4 ]

2 голосов
/ 14 июня 2019

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

Они также анализируют только путь (в стиле URI), как и регулярные выражения, и возвращают второй каталог.

  • Самый простой и эффективный, просто split строка на /

    my $dir = ( split /\//, $path )[2];
    

    split возвращает '' первым (перед первым /), поэтому нам нужен третий элемент. (Обратите внимание, что мы можем использовать альтернативный разделитель для шаблона разделителя, это регулярное выражение: split m{/}, $path.)

  • Используйте соответствующие модули, например URI

    use URI;
    my $dir = ( URI->new($path)->path_segments )[2];
    

    или Mojo :: Path

    use Mojo::Path;
    my $dir = Mojo::Path->new($path)->parts->[1];
    

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

Я проверил их для проверки работоспособности модулей.

split либо превосходит регулярное выражение на 10-15% (регулярное выражение, использующее отрицательный символьный класс и класс, основанный на не жадном .+?, встречаются одинаково), либо примерно одинаково с ними. Они быстрее, чем Mojo примерно на 30%, и только URI серьезно отстают, в 5 раз от Mojo.

Это для путей, типичных для реальных URL, с несколькими короткими компонентами. С только двумя очень длинными строками (10 тыс. Символов) Mojo::Path (что удивительно для меня) в шесть раз опережает split (!), Который опережает регулярное выражение класса символов более чем на порядок.

Регулярное выражение класса отрицательных символов для таких длинных строк превосходит не жадного (.+?) в 3 раза, что полезно знать само по себе.

Во всем этом объекты URI и Mojo были созданы один раз, заранее.


Код теста. Я хотел бы отметить, что детали этих временных параметров гораздо менее важны, чем структура и качество кода.

use warnings;
use strict;
use feature 'say';
use URI;
use Mojo::Path;
use Benchmark qw(cmpthese);

my $runfor = shift // 3;  #/    
#my $path = '/' . 'a' x 10_000 . '/' . 'X' x 10_000;
my $path = q(/api/app/v1/method);    
my $uri = URI->new($path);
my $mojo = Mojo::Path->new($path);

sub neg_cc {
    my ($dir) = $path =~ m{ [^/]+ / ([^/]+) }x;      return $dir; #/
}
sub non_greedy {
    my ($dir) = $path =~ m{ .+? / (.+?) (?:/|$) }x;  return $dir; #/  
}
sub URI_path {
    my $dir = ( $uri->path_segments )[2];            return $dir;
}
sub Mojo_path {
    my $dir = $mojo->parts->[1];                     return $dir;
}
sub just_split {
    my $dir = ( split /\//, $path )[2];              return $dir;
}

cmpthese( -$runfor, {
    neg_cc      => sub { neg_cc($path) },
    non_greedy  => sub { non_greedy($path) },
    just_split  => sub { just_split($path) },
    URI_path    => sub { URI_path($path) },  
    Mojo_path   => sub { Mojo_path($path) },  
}); 

При выполнении (10 секунд) этой печати на ноутбуке с v5.16

                Rate   URI_path  Mojo_path non_greedy     neg_cc just_split
URI_path    146731/s         --       -82%       -87%       -87%       -89%
Mojo_path   834297/s       469%         --       -24%       -28%       -36%
non_greedy 1098243/s       648%        32%         --        -5%       -16%
neg_cc     1158137/s       689%        39%         5%         --       -11%
just_split 1308227/s       792%        57%        19%        13%         --

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

1 голос
/ 14 июня 2019

Ваш шаблон ([^\/api]\w*) состоит из группы захвата и класса отрицательных символов, который сначала будет соответствовать 1 раз, а не /, a, p или i. Смотрите демо .

После этого 0+ раз слово char будет совпадать. Например, шаблон может соответствовать только одному символу, который не указан в классе символов.

Что вы можете сделать, это использовать группу захвата и сопоставить \w+

^/(?:api|web)/(\w+)/v1/method

Объяснение

  • ^ Начало строки
  • (?:api|web) Группа без захвата с чередованием. Соответствует API или Web
  • (\w+) Захват группы 1, совпадение с 1 + словом слова
  • /v1/method Совпадение буквально, как в данных вашего примера.

Regex demo

1 голос
/ 14 июня 2019

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

\/(.+?)\/(.+?)\/.*

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

Демонстрация 1

Пример

#!/usr/bin/perl -w

use strict;
use warnings;
use feature qw( say );

main();   

sub main{    
   my $string = '/api/application/v1/method
/web/application/v1/method';
   my $pattern = '\/(.+?)\/(.+?)\/.*';
   my $match = replace($pattern, '$2', $string); 
   say $match , " is a match ??? ";

}        

sub replace {
   my ($pattern, $replacement, $string) = @_;
   $string =~s/$pattern/$replacement/gee;

   return $string;
}

Выход

application
application is a match ???

Советы

Здим рекомендует:

Законный подход, примечания:

(1) нет необходимости в трейлинге. *

(2) Нужно / | $ (не только /), если путь заканчивается без / (чтобы завершить не жадный шаблон в конце строки, если нет /)

(3), обратите внимание, хотячто / ee может быть уязвимо (даже из-за ошибок), поскольку при второй оценке (e) будет выполняться код, если первая оценка приводит к коду.И может быть трудно гарантировать, что это всегда делается под полным контролем.Если говорить более конкретно, для этой цели нет оснований для выполнения подстановки - достаточно просто сопоставить и захватить.

1 голос
/ 14 июня 2019

Общее решение регулярных выражений (синтаксис Perl или PCRE) будет выглядеть следующим образом:

^/[^/]+/([^/]+)

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

Это предпочтительнее не жадных регулярных выражений, потому что не нужно возвращаться назад, и учитывает все остальное, что могут содержаться в разделах, которые могут легко содержать несловарные символы, такие как -, которые не будут совпадать\w.

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