2
votes

Récupère la deuxième chaîne de l'URI avec Perl regex

J'ai besoin d'obtenir la deuxième partie de l'URI, les URI possibles sont:

([^\/web]\w*)

Je peux obtenir "application" en utilisant:

XXX

et

([^\/api]\w*)

Mais je sais que ce n'est pas la meilleure approche, quelle serait la bonne façon?

Merci !

Edit: merci à tous pour la contribution, le but était de placer la deuxième partie de l'URI dans un en-tête dans apache avec des règles de réécriture


2 commentaires

Vous avez tagué ceci avec Perl mais est-ce du code Perl? Parce qu'en Perl, le meilleur moyen serait d'utiliser un module, pas une regex.


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


4 Réponses :


1
votes

Une solution générale de regex (syntaxe Perl ou PCRE) serait:

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

Chaque section est délimitée par / , il suffit donc de capturer autant de code non- / caractères comme il y en a.

Ceci est préférable aux expressions rationnelles non gourmandes car il n'a pas besoin de revenir en arrière et permet tout ce que les sections peuvent contenir, qui peuvent facilement contenir des non- caractères de mots tels que - qui ne seront pas mis en correspondance par \w.


2 commentaires

Bien que la question ne concerne spécifiquement qu'un chemin générique, je pense qu'il vaut toujours la peine de dire que cette solution n'analyse pas un URI (puisqu'ils le mentionnent dans le titre) mais plutôt seulement un chemin avec des barres obliques


Il n'analyse aucun URI: il analyse le composant de chemin d'un URI, comme le sont les exemples dans l'OP.



1
votes

Votre motif ([^ \ / api] \ w *) se compose d'un groupe de capture et d'une classe de caractères annulés qui correspondront d'abord 1 fois et non un / , a , p ou i . Voir la démo .

Après cela, plus de 0 fois un caractère de mot sera mis en correspondance. Le modèle peut par exemple ne correspondre qu'à un seul caractère qui n'est pas répertorié dans la classe de caractères.

Ce que vous pouvez faire est d'utiliser un groupe de capture et de faire correspondre \w+

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

  • ^ Début de chaîne
  • (?: api | web) Groupe non capturant avec alternance. Faites correspondre l'API ou le Web
  • (\ w +) Groupe de capture 1, correspond à plus de 1 caractères de mot
  • / v1 / method Correspond littéralement comme dans vos données d'exemple.

Démo Regex


0 commentaires

1
votes

Il y a tellement d'options que nous pouvons le faire, je ne sais pas laquelle serait la meilleure, mais cela pourrait être aussi simple que:

application
application is a match 💚💚💚

quelle sortie souhaitée est dans la deuxième capture groupe $2.

Démo 1

Exemple

#!/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;
}

Sortie

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

Conseil

zdim informe que:

Une approche légitime, note:

(1) il n'y a pas besoin de la fin. *

(2) Need / | $ (pas seulement /), au cas où le chemin se terminerait sans / (to terminer le modèle non gourmand à la fin de la chaîne, s'il n'y a pas /)

(3) notez bien que / ee peut être vulnérable (même juste aux erreurs), puisque la deuxième évaluation (e) exécutera le code si la première évaluation aboutit au code. Et il peut être difficile de garantir que ce soit toujours fait sous contrôle total. Plus précisément, à cet effet, il y a aucune raison d'exécuter une substitution - il suffit de faire correspondre et capturer.


0 commentaires

2
votes

Avec tous les regex, explicitement demandés, j'aimerais évoquer d'autres approches.

Celles-ci analysent également uniquement un chemin (de style URI), comme les regex, et renvoient le deuxième répertoire. p >

  • Le plus basique et le plus efficace, il suffit de diviser la chaîne sur /

                    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%         --
    

    Le split retourne '' en premier (avant le premier / ) donc nous avons besoin du troisième élément. (Notez que nous pouvons utiliser un autre délimiteur pour le modèle de séparateur, il s'agit de l'expression régulière: split m {/}, $ path .)

  • Utilisez les modules appropriés, par exemple URI

    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) },  
    }); 
    

    ou Mojo :: Path

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

Ce qu'il faut utiliser dépend des détails de ce que vous faites - si vous avez un autre travail avec les URL et le Web, vous voulez clairement des modules pour cela; sinon, ils peuvent (ou non) être exagérés.

Je les ai comparés pour vérifier ce que l'on paie avec les modules.

Le split bat soit le regex jusqu'à 10-15% (le regex utilisant la classe de caractères niée et celui basé sur le code . +? reviennent de la même manière), ou est à peu près la même chose avec eux. Ils sont plus rapides que Mojo d’environ 30% , et seul URI est sérieusement en retard, d’un facteur 5 derrière Mojo code >.

C'est pour les chemins typiques pour les URL réelles, avec une poignée de composants courts. Avec seulement deux très longues chaînes (10k caractères), Mojo :: Path (étonnamment pour moi) est un facteur de six devant split (!), Qui est en avance sur expression régulière de classe de caractère de plus d'un ordre de grandeur.

Le regex de classe de caractère négé pour des chaînes aussi longues bat le non gourmand (. +? ) un par un facteur de 3, bon à savoir en soi.

Dans tout cela, les objets URI et Mojo ont été créés une fois, à l'avance.


Code de référence. Je voudrais noter que les détails de ces timings sont beaucoup moins importants que la structure et la qualité du code.

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

Avec une exécution de (10 secondes) cette impression, sur un ordinateur portable avec la version 5.16

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

Il faut garder à l'esprit que la surcharge de l'appel de fonction est très importante pour un travail aussi simple, et malgré Benchmark 's ces chiffres sont probablement mieux considérés comme un guide rapide.


9 commentaires

Ceci est une URL; File :: Spec ne serait pas approprié, mais URI et Mojo :: URL le seraient.


@Grinnz nah, à part laisser tomber le mot "URI", ils ne nous ont donné aucun indice, aucun schéma; ils demandent l'expression régulière et toutes les réponses, y compris la vôtre, analysent simplement un chemin (à juste titre, car c'est tout ce qui est donné). Btw. Je n'ai vu aucune méthode appropriée dans URI (ce qui serait de toute façon un exagéré); même chose avec Mojo. Je suis spécifiquement allé chercher quelque chose pour que je puisse supporter l'utilisation d'un module, et j'ai fini avec le simple ' File :: Spec (quelque peu décevant).


@Grinnz Si vous connaissez un module qui analyse le chemin "hôte" dans le contexte de l'URI et de manière pratique, je serai heureux de l'ajouter. (Ou si j'ai manqué quelque chose de URI )


@Grinnz Je suis curieux, avez-vous remarqué la dernière phrase (de la partie principale) dans ma réponse? Eh bien, et les deux premiers vraiment - je précise qu'il ne s'agit que d'analyser un chemin, non?


Ma réponse concerne spécifiquement un chemin d'URL que l'OP pose clairement. Les chemins de système de fichiers nécessitent la portabilité fournie par File :: Spec, telle que (le plus souvent) autoriser les contre-obliques comme séparateurs et autoriser les étiquettes de volume sous Windows.


Mojo :: Path est spécifiquement pour analyser cette partie d'une URL, donc pourrait être utilisé pour cela: Mojo :: Path-> new ('/ api / application / v1 / method') -> parts -> [1 ] . Pour l'URI, vous utiliseriez path_segments, qui commence par un vide: (URI-> new ('/ api / application / v1 / method') -> path_segments) [2]


Les chemins du système de fichiers et les chemins URI ne sont généralement pas compatibles car le premier dépend du système et le second ne l'est pas; le module URI :: file existe pour convertir entre les deux en tenant compte de l'OS (avec le fichier: schéma bien sûr).


@Grinnz Ah, OK, vous vouliez dire le point de portabilité. J'étais d'accord avec ça ... mais j'ai manqué path_segments (je l'ai essayé ...? .. apparemment pas bien), et je ne connaissais pas Mojo :: Path < / code>. Mettra à jour sous peu, merci.


D'après l'expérience passée, la lenteur de l'URI n'est pas du tout surprenante.