Question

Given a string like "/foo/bar/baz/quux" (think of it like a path to a file on a unixy system), how could I (if at all possible) formulate a regular expression that gives me all possible paths that can be said to contain file quux?

In other words, upon running a regexp against the given string ("/foo/bar/baz/quux"), I would like to get as results:

  • "/foo/"
  • "/foo/bar/"
  • "/foo/bar/baz/"

I've tried the following:

  • '/\/.+\//g' - this is greedy by default, matches "/foo/bar/baz/"
  • '/\/.+?\//g' - lazy version, matches "/foo/" and also "/baz/"

P.S.: I'm using Perl-compatible Regexps in PHP in function preg_match(), for that matter)

Was it helpful?

Solution

Felipe not looking for /foo/bar/baz, /bar/baz, /baz but for /foo, /foo/bar, /foo/bar/baz

One solution building on regex idea in comments but give the right strings:

  • reverse the string to be matched: xuuq/zab/rab/oof/ For instance in PHP use strrev($string )

  • match with (?=((?<=/)(?:\w+/)+))

This give you

zab/rab/oof/
rab/oof/
oof/

Then reverse the matches with strrev($string)

This give you

/foo/bar/baz
/foo/bar
/foo

If you had .NET not PCRE you could do matching right to left and proably come up with same.

OTHER TIPS

This solution will not give exact output as you are expecting but still give you pretty useful result that you can post-process to get what you need:

$s = '/foo/bar/baz/quux';
if ( preg_match_all('~(?=((?:/[^/]+)+(?=/[^/]+$)))~', $s, $m) )
   print_r($m[0]);

Working Demo

OUTPUT:

Array
(
    [0] => /foo/bar/baz
    [1] => /bar/baz
    [2] => /baz
)

Completely different answer without reversing string.

(?<=((?:\w+(?:/|$))+(?=\w)))

This matches

foo/
foo/bar/
foo/bar/baz/

but you have to use C# which use variable lookbehind not PCRE

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top