Reputation: 5052
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!
Upvotes: 1
Views: 140
Reputation: 5052
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;
}
}
Upvotes: 0
Reputation: 114
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...
}
Upvotes: 1