Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP preg_grep reverse matching pattern

Tags:

regex

php

I built a simple code which parses all music folders inside several disks and put the list into an array.

The folders names begin with multiple spaces when they are categories, with a single space when they are "final folders". E.g. see this structure:

[0] => /Volumes/SAMPLES/  VOCALS/
[1] => /Volumes/SAMPLES/  VOCALS/  AFRICA/
[2] => /Volumes/SAMPLES/  VOCALS/ AcmeInc Club Vocals/
[3] => /Volumes/SAMPLES/  VOCALS/ AtomicInc Dance Vocals/
[4] => /Volumes/SAMPLES/  VOCALS/  AFRICA/ AfroInc Zulu Vocals/
[5] => /Volumes/SAMPLES/  VOCALS/  AFRICA/ SampleInc Warriors/
[6] => /Volumes/SAMPLES/  VOCALS/  AFRICA/ SampleInc Warriors/SampleInc_Warriors_Ululation/
[7] => /Volumes/SAMPLES/  VOCALS/  AFRICA/ SampleInc Warriors/SampleInc_Warriors_Drums/

and so on... I need to select the final folders only and tried several combinations of greedy and non greedy patterns, starting from the final $ E.g. the following path doesn't work:

$pattern = "#\/ ([:alnum:]+?)/$#i";
$matches  = preg_grep ($pattern, $root);

The expected result should have been:

[3] => /Volumes/SAMPLES/  VOCALS/ AcmeInc Club Vocals/
[4] => /Volumes/SAMPLES/  VOCALS/ AtomicInc Dance Vocals/
[5] => /Volumes/SAMPLES/  VOCALS/  AFRICA/ AfroInc Zulu Vocals/
[6] => /Volumes/SAMPLES/  VOCALS/  AFRICA/ SampleInc Warriors/

Instead I get all the folders or none or orphans. Please consider that special chars like &or ! could be in the folder name. Thank you for the suggestions, 3 days,tried everything, desperate, thanks!

like image 475
fab Avatar asked Sep 27 '22 10:09

fab


1 Answers

Here is a working regex:

'~/(?:  +[^/\s]+)*/ [^/\s]+(?: +[^/\s]+)*/$~'

See regex demo

It matches:

  • /(?: +[^/\s]+)* - a non-final subfolder (/, then more than 1 spaces, 1 or more characters other than space or /)
  • / - a forward slash with a space after it
  • [^/\s]+ - 1 or more characters other than a whitespace or forward slash
  • (?: +[^/\s]+)* - 0 or more sequences of ...
    • + - 1 or more regular spaces
    • [^/\s]+ - 1 or more characters other than a whitespace or forward slash
  • / - a forward slash
  • $ - end of string

See PHP code demo:

$ar = array("/Volumes/SAMPLES/  VOCALS/", 
    "/Volumes/SAMPLES/  VOCALS/  AFRICA/",
    "/Volumes/SAMPLES/  VOCALS/ AcmeInc Club Vocals/",
    "/Volumes/SAMPLES/  VOCALS/ AtomicInc Dance Vocals/",
    "/Volumes/SAMPLES/  VOCALS/  AFRICA/ AfroInc Zulu Vocals/",
    "/Volumes/SAMPLES/  VOCALS/  AFRICA/ SampleInc Warriors/",
    "/Volumes/SAMPLES/  VOCALS/  AFRICA/ SampleInc Warriors/SampleInc_Warriors_Ululation/",
    "/Volumes/SAMPLES/  VOCALS/  AFRICA/ SampleInc Warriors/SampleInc_Warriors_Drums/",
    "/Volumes/SAMPLES/  VOCALS/  AFRICA/ AfroInc Zulu Vocals/ Folder1/"
    );
$n = preg_grep('~/(?:  +[^/\s]+)*/ [^/\s]+(?: +[^/\s]+)*/$~', $ar);
print_r($n);

Result:

Array
(
    [2] => /Volumes/SAMPLES/  VOCALS/ AcmeInc Club Vocals/
    [3] => /Volumes/SAMPLES/  VOCALS/ AtomicInc Dance Vocals/
    [4] => /Volumes/SAMPLES/  VOCALS/  AFRICA/ AfroInc Zulu Vocals/
    [5] => /Volumes/SAMPLES/  VOCALS/  AFRICA/ SampleInc Warriors/
)
like image 65
Wiktor Stribiżew Avatar answered Sep 30 '22 07:09

Wiktor Stribiżew