简体   繁体   中英

PHP preg_grep reverse matching pattern

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". Eg 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 $ Eg 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!

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/
)

You only need to ensure that the next character after the space is not a space too.

$result = preg_grep('~/ [^/ ][^/]*/\z~', $root);

pattern details:

/          # literal slash
[ ]        # literal space
[^/ ]      # a character except a slash or a space
[^/]*      # zero or more characters that are not a slash
/          # literal slash
\z         # end of the string

demo

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM