Creating files: Replacing text

  1. Creating folders
  2. Creating files
  3. Try to break it

If you play around with export now, you’ll find that some exports don’t work. Go ahead and try:

./show --artist afroman --export genre songs.txt

What you should get back is:

Unable to open Hip Hop/Rap

: No such file or directory

There are two problems here. One, why is that error message separated onto two lines? It looks like we’re printing a new line between the export file name and the colon, but if you look in the code there is no such new line. The second, why would it tell us that there is no such file? We know that: that’s why we’re trying to create it.

The first problem is an easy one to fix. That new line is in the genre name itself. The genre is the last field on the line. When we get a line of text from a file in Perl, Perl includes the line break at the end of the line. When we split the line on tabs, the last item gets this line break, and that last item is the genre.

In front of the split line where we get song, duration, artist, etc., add:

chomp;

This will chomp any line endings off of the end of the current line. If you want to chomp the line endings off of a specific variable, you can use “chomp($variable)”. If you want to chomp the line endings off of a list of variables, you can use “chomp(@list)” or “chomp($variable1, $variable2, etc.)”.

Because we’re chomping the line endings off of the current line, we need to change the raw format as well. Change “$text = $_;” to:

$text = "$_\n";

Now the error message is easier to read:

Unable to open Hip Hop/Rap: No such file or directory

The problem here is that Unix uses the slash to separate directory names from each other and from the file name. Perl thinks the script wants to create a file called “Rap” in a folder called “Hip Hop”. There is no folder called “Hip Hop”, so this fails with that error.

We need to get rid of that slash. There is another form of regular expression that does this for us. Let’s add a general subroutine for replacing characters in a piece of text:

sub replace {
my($text, $from, $to) = (shift, shift, shift);

$text =~ s/$from/$to/g;

return $text;
}

Remember that we already know what shift does. Here, we’re just doing it three times in a row to grab each of the three items we will send this subroutine: the text we want to change, the characters we want to look for in that text, and the characters we want to replace it with. If we call “replace("omega man", "m", "d")”, we would expect to get back “odega dan”.

$text =~ s/$from/$to/g;

The “=~” means that this is a regular expression. The “s” in front of the first slash means that this is a substitution. By default regular expressions only match, they don’t perform any changes. A substitution will. In order to substitute, it needs to know what to substitute. That’s between the second slash and the new third slash. What we have here as $to will replace $from in $text.

By default, substitutions will only make one substitution. If we want the regular expression to affect all occurrences of $from, we need to specify that this is a global replace. The “g” after the final slash does this. The “g” is a modifier much like “i” for case insensitive matches.

If we want this to also be case insensitive, we could also add the “i” there too:

$text =~ s/$from/$to/gi;

What we want is to replace slashes with dashes, so replace “$matches[$#matches]{'file'} = $$exportField if $exportField;” with:

if ($exportField) {
$filename = $$exportField;
$filename = replace($filename, "/", "-");
$matches[$#matches]{'file'} = $filename;
}

If we run the Afroman export again:

./show --artist afroman --export genre songs.txt

We now have a file called “Hip Hop-Rap”.

You might choose a different character to replace slashes. It must be a valid character for your operating system or you’ll continue to get some sort of error.

  1. Creating folders
  2. Creating files
  3. Try to break it