简体   繁体   中英

How to get parts of a string using multiple patterns in PHP? [Answer: Use a regular expression, but how exactly?]

I know there are similar questions, (this one " How do you use a variable in a regular expression? " seems to be close), but I want to know (the best way) how to fix my problem.

I have some patterns defined which I use to detect an artist and a title in some file names (of MP3 and other audio files). It is similar the way MP3tag (a well known Windows application) converts filenames into MP3 tags. How to do this?

Below a small test application. (Negative cases are missing, but you get the grip.)

<?php

define('SEARCHPATTERNS', array(
    '%track%. %artist% - %title%',
    '%track% - %artist% - %title%',
    '%track%. %title%',
    '%track% - %title%',
    '%title%'));

define('UNKNOWN_ARTIST_TITLE_ARRAY', array('?', '?'));

$fileNames = array(
    '0780. Janis Joplin - Mercedes Benz.mp3',
    '0780. Janis Joplin - Mercedes Benz.flac',

    '0780 - Janis Joplin - Mercedes Benz.mp3',
    '0780 - Janis Joplin - Mercedes Benz.flac',

    '0780. Mercedes Benz.mp3',
    '0780. Mercedes Benz.flac',

    '0780 - Mercedes Benz.mp3',
    '0780 - Mercedes Benz.flac',

    'Mercedes Benz.mp3',
    'Mercedes Benz.flac',
);

//Test some file names 
foreach($fileNames as $fileName)
{
    $titleAndArtist = GetTitleArtistUsingSearchPattern($fileName);
    var_dump($titleAndArtist);    
}

function GetTitleArtistUsingSearchPattern($fileName)
{
    foreach(SEARCHPATTERNS as $pattern)
    {
        $artist = '???????????'; //  Get it from fileName if it matches the pattern, but how?
        $title = '???????????'; //  Get it from fileName if it matches the pattern, but how?

        if(true) // If is matches.... How?
        {
            return array(
                empty($artist) ? UNKNOWN_ARTIST_TITLE_STRINGS[0] : $artist,
                empty($title) ? UNKNOWN_ARTIST_TITLE_STRINGS[1] : $title
            );
        } 
    }

    return UNKNOWN_ARTIST_TITLE_ARRAY;    

}

?>

I am quite sure I have to use a regular expression search (regex) for this. I cannot think clearly right now (thanks to Corona). Help me out please. Very much appreciated!

I did something like this before for a script that helped me tag my music collection. I used Named Capturing Groups .

You just need to define the patterns that will match the different parts of the file inside the structure: (?P<name>pattern) . Where name is a tag that describes the pattern.

Example:

$patterns = [
  //This will match `00. artist - title.ext`
  '/(?P<track>[0-9]{2})\.\s(?P<artist>.+)\s-\s(?P<title>.+)\.([a-z0-9]{3,4})/i',
  //This will match `00. title.ext`
  '/(?P<track>[0-9]{2})\.\s(?P<title>.+)\.([a-z0-9]{3,4})/i',
  //This will match `artist - album - 00 title.ext`
  '/(?P<artist>.+)\s-\s(?P<album>.+)\s-\s(?P<track>[0-9]{2})\s(?P<title>.+)\.[a-z0-9]{3,4}/i'

  // and so on...
];

$filename = "01. Cool Band - Song Title.flac";
$matches = [];
foreach($patterns as $pattern) {
  preg_match($pattern, $filename, $matches);

  //Matched artist?
  $artist = $matches['artist'] ?? false;

  //Matched song title?
  $title = $matches['title'] ?? false;

  //Matched album?
  $album = $matches['album'] ?? false;

  //etc...
}

The solution is basically what David Gomez suggested. Works like a charm. I can't imagine their are many other good solutions for this particular problem. Here's my implementation (part of a class):

private function GetTrackInfoFromFileName($fileName, &$item,  $defaultValue = '?')
{
    $patterns = array(          
        '/(?P<track>\d{1,4})\.\s(?P<artist>.+)\s-\s(?P<title>.+)\.([a-z0-9]{3,4})/i', //Matches `0000. artist - title.ext`
        '/(?P<track>\d{1,4})\s-\s(?P<artist>.+)\s-\s(?P<title>.+)\.([a-z0-9]{3,4})/i', //Matches `0000 - artist - title.ext`
        '/(?P<artist>.+)\s-\s(?P<title>.+)\.([a-z0-9]{3,4})/i', //Matches `artist - title.ext`
        '/(?P<track>\d{1,4})\.\s(?P<title>.+)\.([a-z0-9]{3,4})/i', //Matches `0000. title.ext`
    ); 

    $matches = [];

    foreach($patterns as $pattern)
    {
        preg_match($pattern, $fileName, $matches);
        if(empty($matches))
        {
            continue;
        }
        $item['artist'] = $matches['artist'] ?? $defaultValue;
        $item['title'] = $matches['title']  ?? $defaultValue;
        $item['track'] = isset($matches['track']) ? array($matches['track']) : array($defaultValue);
        return;
    }
}

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