web-dev-qa-db-fra.com

Regex pour analyser répertoire et nom de fichier

J'essaie d'écrire une regex qui analysera le répertoire et le nom de fichier d'un chemin complet en utilisant des groupes correspondants.

alors...

/var/log/xyz/10032008.log

reconnaîtrait group 1 to be "/var/log/xyz" et group 2 to be "10032008.log"

Cela semble simple, mais je ne parviens pas à faire en sorte que les groupes correspondants travaillent toute ma vie.

REMARQUE: comme l'ont fait remarquer certains répondants, il ne s'agit probablement pas d'un bon usage des expressions régulières. Généralement, je préférerais utiliser l'API de fichier du langage que j'utilisais. Ce que j'essaie en réalité de faire est un peu plus compliqué que cela, mais cela aurait été beaucoup plus difficile à expliquer. J'ai donc choisi un domaine que tout le monde connaîtrait afin de décrire de manière succincte le problème fondamental.

23
Mike Deck

Essaye ça:

^(.+)/([^/]+)$
30
Jeremy Ruten

Dans les langues qui prennent en charge les expressions régulières avec les groupes ne faisant pas de capture :

((?:[^/]*/)*)(.*)

Je vais expliquer la regex géniale en l'explosant ...

(
  (?:
    [^/]*
    /
  )
  *
)
(.*)

Que signifient les parties:

(  -- capture group 1 starts
  (?:  -- non-capturing group starts
    [^/]*  -- greedily match as many non-directory separators as possible
    /  -- match a single directory-separator character
  )  -- non-capturing group ends
  *  -- repeat the non-capturing group zero-or-more times
)  -- capture group 1 ends
(.*)  -- capture all remaining characters in group 2

Exemple

Pour tester l'expression régulière, j'ai utilisé le script Perl suivant ...

#!/usr/bin/Perl -w

use strict;
use warnings;

sub test {
  my $str = shift;
  my $testname = shift;

  $str =~ m#((?:[^/]*/)*)(.*)#;

  print "$str -- $testname\n";
  print "  1: $1\n";
  print "  2: $2\n\n";
}

test('/var/log/xyz/10032008.log', 'absolute path');
test('var/log/xyz/10032008.log', 'relative path');
test('10032008.log', 'filename-only');
test('/10032008.log', 'file directly under root');

La sortie du script ...

/var/log/xyz/10032008.log -- absolute path
  1: /var/log/xyz/
  2: 10032008.log

var/log/xyz/10032008.log -- relative path
  1: var/log/xyz/
  2: 10032008.log

10032008.log -- filename-only
  1:
  2: 10032008.log

/10032008.log -- file directly under root
  1: /
  2: 10032008.log
14
Chad Nouis

La plupart des langues ont des fonctions d’analyse de chemin qui vous donneront déjà cela. Si vous en avez la possibilité, je vous recommanderais d'utiliser ce qui vous est offert gratuitement, immédiatement après utilisation.

En supposant/est le délimiteur de chemin ...

^(.*/)([^/]*)$

Le premier groupe sera quelle que soit l'information sur le répertoire/chemin, le second sera le nom du fichier. Par exemple:

  • /foo/bar/baz.log : "/ foo/bar /" est le chemin, "baz.log" est le fichier.
  • foo/bar.log : "foo /" est le chemin, "bar.log" est le fichier
  • /foo/bar : "/ foo /" est le chemin, "bar" est le fichier
  • /foo/bar/: "/ foo/bar /" est le chemin et il n'y a pas de fichier.
8
Travis Illig

Quelle langue? et pourquoi utiliser regex pour cette tâche simple?

Si vous devez:

^(.*)/([^/]*)$

vous donne les deux parties que vous vouliez. Vous devrez peut-être citer les parenthèses:

^\(.*\)/\([^/]*\)$

en fonction de la syntaxe de votre langue préférée.

Mais je vous suggère simplement d’utiliser la fonction de recherche de chaîne de votre langue qui trouve le dernier caractère "/" et de scinder la chaîne sur cet index.

4
tzot

Et ça?

[/]{0,1}([^/]+[/])*([^/]*)

Déterministe:

((/)|())([^/]+/)*([^/]*)

Strict :

^[/]{0,1}([^/]+[/])*([^/]*)$
^((/)|())([^/]+/)*([^/]*)$
1
Aurélien Ooms

Essaye ça:

/^(\/([^/]+\/)*)(.*)$/

Cela laissera la barre oblique finale sur le chemin, cependant.

0
Lucas Oman

Une réponse très tardive, mais espérons que cela aidera

^(.+?)/([\w]+\.log)$

Cela utilise la vérification paresseuse pour /, et je viens de modifier la réponse acceptée

http://regex101.com/r/gV2xB7/1