-1

I'm working on a song database application with an existing database. In the editor the songs are laid out like this in the contents column:

[chorus]
And all will surely agree,
There's nothing like PHP.
[1]
It may not be the best way,
But it isn't going away.
[2]
When you don't appear to hack it,
Check for a closing bracket.
[bridge]
Oh, if you don't like this ode,
Then please don't look at my code.

The sequence column then contains the order of the song which for this might be 1,c,2,c,b,1,c (where the numbers are the verse numbers and b and c are the bridge and chorus).

I want to read the database and assemble the song into the right order with a blank line between sections. I figured the best way was to split the song into an associative array and then loop through the sequence adding the associated parts to the output.

How should I do this? I thought that the parse_ini_string() function might make it easy as the section heads are in [ ] but I suspect that it's looking for var=something; on each line after the section head.

How best could I do this?


Notes:

I would use another associative array to match the section heads to their sequence abbreviations.

$sequenceCodes = array(
    "1" => "verse 1",
    "2" => "verse 2",
    "3" => "verse 3",
    ...
    "p" => "prechorus",
    "c" => "chorus",
    "b" => "bridge",
    "e" => "ending",
);
6
  • 1
    Split the string into lines. Loop through the lines. If the line matches [...], start a new array element with that key. If not, concatenate the line onto the current array element.
    – Barmar
    Commented Nov 21 at 23:42
  • 1
    Your $sequenceCodes array doesn't really match the data. For the verses, the keys correspond to what's in[] in the text. But for the named sections, the names correspond to the values.
    – Barmar
    Commented Nov 21 at 23:44
  • Thanks. I'll try a regex with \[[^\]]*\] and see how I get on. I haven't started debugging the $sequenceCodes yet but I should be able to fix it. Post your comment as an answer and I'll accept it (subject to testing in the morning!).
    – Transistor
    Commented Nov 21 at 23:56
  • I 💯 advise you to use a string format which is more portal than this non-standard format. Your database is not responsible for holding data in a user-friendly format. The database must be kept lean and searchable. Use a json column or another normalized table (one-to-many). This whole task smells of XY Problem to me. Commented Nov 22 at 2:33
  • Thanks, @mickmackusa. The database isn't mine so and the structure (and data entry) is determined by a Windows application. I just want to read it with a web app.
    – Transistor
    Commented Nov 22 at 9:39

1 Answer 1

1

This is a wicked, wicked XY Problem that should be refactored because you've forced yourself to tackle a problem which is harder than it should be.

It would be more ideal to store your contents data in a normalized fashion or a more simply parsed format. That said, here is a regex parsing approach to extract the first character of labels then match subsequent lines, then strtr() will render the sequence output. Demo

$contents = <<<INI_ISH
[chorus]
And all will surely agree,
There's nothing like PHP.
[1]
It may not be the best way,
But it isn't going away.
[2]
When you don't appear to hack it,
Check for a closing bracket.
[bridge]
Oh, if you don't like this ode,
Then please don't look at my code.
INI_ISH;

preg_match_all(
    '#^\[([^\]])[^\]]*\]\R\K(?:(?!^\[).)*$#ms',
    $contents,
    $m
);
$map = array_combine($m[1], $m[0]);
$map[','] = "\n\n";

$sequence = '1,c,2,c,b,1,c';

echo strtr($sequence, $map);

Output:

It may not be the best way,
But it isn't going away.

And all will surely agree,
There's nothing like PHP.

When you don't appear to hack it,
Check for a closing bracket.

And all will surely agree,
There's nothing like PHP.

Oh, if you don't like this ode,
Then please don't look at my code.

It may not be the best way,
But it isn't going away.

And all will surely agree,
There's nothing like PHP.
3
  • This is super compact, thanks, and uses a few tricks that are new to me. (I'm a retired automation engineer and I used PHP over the years to present information from machines, etc., but don't have formal training.) I'm working through the code and studying the documentation for functions that I haven't used before. Can you explain the operation of $map[','] = "\n\n";? (It's a difficult one to web search!)
    – Transistor
    Commented Nov 22 at 11:55
  • I just wanted to add double spaces between pieces of songs, so I replace commas with two newlines. Comment out that declaration to see how the output is affected. Commented Nov 22 at 12:05
  • I've got it! The use of preg_match_all(), array_combine() and strtr() were all new to me and very powerful. Thank you again. As mentioned in the comments to the question, the database design isn't mine so this solution provides an easy workaround.
    – Transistor
    Commented Nov 22 at 14:13

Not the answer you're looking for? Browse other questions tagged or ask your own question.