Reputation: 166
Let’s say I have the string http://www.example.com/images/[1-12].jpg
. I would like to expand it into:
http://www.example.com/images/1.jpg
http://www.example.com/images/2.jpg
http://www.example.com/images/3.jpg
http://www.example.com/images/4.jpg
http://www.example.com/images/5.jpg
http://www.example.com/images/6.jpg
http://www.example.com/images/7.jpg
http://www.example.com/images/8.jpg
http://www.example.com/images/9.jpg
http://www.example.com/images/10.jpg
http://www.example.com/images/11.jpg
http://www.example.com/images/12.jpg
Here is my code:
$str = "http://www.example.com/images/[1-12].jpg";
while(preg_match_all("/^([^\\[\\]]*)\\[(\\d+)\\-(\\d+)\\](.*)$/m", $str, $mat)){
$arr = array();
$num = sizeof($mat[0]);
for($i = 0; $i < $num; $i++){
for($j = $mat[2][$i]; $j <= $mat[3][$i]; $j++){
$arr[] = rtrim($mat[1][$i].$j.$mat[4][$i]);
}
}
$str = implode(PHP_EOL, $arr);
}
It works fine even if I change $str
to a more complex expression like the following:
$str = "http://www.example.com/images/[1-4]/[5-8]/[9-14].jpg";
But, unfortunately, zero-padded integers are not supported. So, if I begin with:
$str = "http://www.example.com/images/[001-004].jpg";
Expected result:
http://www.example.com/images/001.jpg
http://www.example.com/images/002.jpg
http://www.example.com/images/003.jpg
http://www.example.com/images/004.jpg
And the actual result:
http://www.example.com/images/001.jpg
http://www.example.com/images/2.jpg
http://www.example.com/images/3.jpg
http://www.example.com/images/4.jpg
How to change this behaviour so that my code produces the expected result? Also, what are the other shortcomings of my code? Should I really do it with the while
loop and preg_match_all
or are there faster alternatives?
UPDATE: Changing the seventh line of my code into
$arr[] = rtrim($mat[1][$i].str_pad($j, strlen($mat[2][$i]), 0, STR_PAD_LEFT).$mat[4][$i]);
seems to do the trick. Thanks a lot to sjagr for suggesting this. My question is still open because I would like to know the shortcomings of my code and faster alternatives (if any).
Upvotes: 4
Views: 140
Reputation:
A faster alternative with preg_split
which also supports descending order (FROM > TO):
$str = "http://www.example.com/images/[12-01].jpg";
$spl = preg_split("/\\[([0-9]+)-([0-9]+)\\]/", $str, -1, 2);
$size = sizeof($spl);
$arr = array("");
for($i = 0; $i < $size; $i++){
$temp = array();
if($i%3 == 1){
$range = range($spl[$i], $spl[$i+1]);
$len = min(strlen($spl[$i]), strlen($spl[++$i]));
foreach($arr as $val){
foreach($range as $ran){
$temp[] = $val.str_pad($ran, $len, 0, 0);
}
}
}
else{
foreach($arr as $val){
$temp[] = $val.$spl[$i];
}
}
$arr = $temp;
}
$str = implode(PHP_EOL, $arr);
print($str);
It has the following result:
http://www.example.com/images/12.jpg
http://www.example.com/images/11.jpg
http://www.example.com/images/10.jpg
http://www.example.com/images/09.jpg
http://www.example.com/images/08.jpg
http://www.example.com/images/07.jpg
http://www.example.com/images/06.jpg
http://www.example.com/images/05.jpg
http://www.example.com/images/04.jpg
http://www.example.com/images/03.jpg
http://www.example.com/images/02.jpg
http://www.example.com/images/01.jpg
Upvotes: 1
Reputation: 16502
Per @SoumalyoBardhan's request, my suggestion/answer:
If you use str_pad()
, you can force the padding based on the size of the matched string using strlen()
found by your match. Your usage of it looks good to me:
$arr[] = rtrim($mat[1][$i].str_pad($j, strlen($mat[2][$i]), 0, STR_PAD_LEFT).$mat[4][$i]);
I really can't see what else could be improved with your code, although I don't exactly understand how preg_match_all
would be used in a while
statement.
Upvotes: 2