3

This is probably an easy one, but I couldn't figure it out after searching. I managed to alter the output 20 different ways, but none of them were what I want from it =D

<?php

$text = <<<DATA
Show.Name.2x05.HDTV.x264
Show.Name.2x06.HDTV.x264
Show.Name.2x07.HDTV.x264
Show.Name.2x08.HDTV.x264
Show.Name.2x09.HDTV.x264
DATA;

$text = preg_replace('/([0-9]{1,2})x([0-9]{2})/e',
                 'sprintf("S%02dE%02d", $1, $2)', $text);
echo $text;
?>

Output

Show.Name.S02E05.HDTV.x264
Show.Name.S02E06.HDTV.x264
Show.Name.S02E07.HDTV.x264
Show.Name.S02E00.HDTV.x264
Show.Name.S02E00.HDTV.x264

As you can see it turns my 08 and 09 into 00, my best guess is this is related to PHP thinking I'm trying to indicate octal, as it is a base8 system it only likes 0-7. I didn't think a leading zero in a "string" would indicate that though? How can I alter my code to accept 08 and 09 but not change them to 00? I tried a few ways to try and escape it but i'm stuck.

Giacomo1968
  • 25,759
  • 11
  • 71
  • 103

3 Answers3

3

Try this instead using preg_replace_callback—since the e modifier for preg_replace is now deprecaiated—and str_pad:

$text = <<<DATA
Show.Name.2x05.HDTV.x264
Show.Name.2x06.HDTV.x264
Show.Name.2x07.HDTV.x264
Show.Name.2x08.HDTV.x264
Show.Name.2x09.HDTV.x264
DATA;

$text = preg_replace_callback('/([0-9]{1,2})x([0-9]{2})/', function($matches) {
  return 'S'.(str_pad($matches[1], 2, 0, STR_PAD_LEFT)).'E'.(str_pad($matches[2], 2, 0, STR_PAD_LEFT));
}, $text);

echo '<pre>';
echo $text;
echo '</pre>';

And the output is:

Show.Name.S02E05.HDTV.x264
Show.Name.S02E06.HDTV.x264
Show.Name.S02E07.HDTV.x264
Show.Name.S02E08.HDTV.x264
Show.Name.S02E09.HDTV.x264
Giacomo1968
  • 25,759
  • 11
  • 71
  • 103
3

Currently what you are doing is: sprintf("S%02dE%02d", 2, 05) which is using octal. You're getting octal results because you need to treat the numbers with leading zeros as strings before you parse them rather than execute them directly. Thus the easy solution which you were seeking is simply to quote them like so:

$text = preg_replace('/([0-9]{1,2})x([0-9]{2})/e',
    'sprintf("S%02dE%02d", "$1", "$2")', $text);

Alternatively, since the e flag is depreciated, try using preg_replace_callback which is easier to work with:

$text = preg_replace_callback('/([0-9]{1,2})[x]([0-9]{2})/',
    function($matches){return sprintf("S%02dE%02d", $matches[1], $matches[2]);}
, $text);
Ultimater
  • 4,647
  • 2
  • 29
  • 43
  • It seems you and I came up with almost identical second expressions independently. Can you explain why `$matches[2]` (which is a string) does not get interpreted as octal? Also - based on a comment by OP below my answer, you may want to change the second quantifier to `{1,2}`. – Floris Dec 25 '13 at 23:17
  • @Floris It all has to do with how the `e` modifier handles the callback. You'd think it turns the string into an expression first then uses $1 and $2 as variables. This is not the case because $1 and $2 are not valid variable names for an expression and would produce a syntax error. Rather the $1 and $2 get replaced first with their content: `sprintf("S%02dE%02d", 2, 05)` then only afterwards is this string evaluated and executed and the result used as the replacement text for preg_replace. – Ultimater Dec 25 '13 at 23:28
  • This behavior makes it impossible to preserve string content without resorting to unorthodox workarounds which explains why the feature is now depreciated. – Ultimater Dec 25 '13 at 23:36
  • Thanks for explaining it Ultimater, this is the solution i was looking for, quoting them as indicated functions with the result I was seeking. – frozenthorn Dec 26 '13 at 02:30
1

Keeping with your code

<?php

$text = <<<DATA
Show.Name.2x05.HDTV.x264
Show.Name.2x06.HDTV.x264
Show.Name.2x07.HDTV.x264
Show.Name.2x08.HDTV.x264
Show.Name.2x09.HDTV.x264
DATA;

$text = preg_replace('/(\\\\.[0-9]{1,2})(x[0-9]{2})/e',
                 'sprintf("S%02dE%02d", ltrim($1,\'.\', ltrim($2,\'x\'))', $text);
echo $text;
?>

Works

But as others have suggested, the /e modifier is deprecated.

The reason this happens is due to the $2 (and the $1 but its not seen in your example) variable starting with a 0 and being treated as octal from the php manual

http://www.php.net/manual/en/language.types.integer.php

edit: Ultimater answer is much better

exussum
  • 18,275
  • 8
  • 32
  • 65