6

I am parsing a string before sending it to a DB. I want to go over all <br> in that string and replace them with unique numbers that I get from an array followed by a newLine.

For example:

str = "Line <br> Line <br> Line <br> Line <br>"
$replace = array("1", "2", "3", "4");

my function would return 
"Line 1 \n Line 2 \n Line 3 \n Line 4 \n"

Sounds simple enough. I would just do a while loop, get all the occurances of <br> using strpos, and replace those with the required numbers+\n using str_replace.

Problem is that I always get an error and I have no idea what I am doing wrong? Probably a dumb mistake, but still annoying.

Here is my code

$str     = "Line <br> Line <br> Line <br> Line <br>";
$replace = array("1", "2", "3", "4");
$replaceIndex = 0;

while(strpos($str, '<br>') != false )
{
    $str = str_replace('<br>', $replace[index] . ' ' .'\n', $str); //str_replace, replaces the first occurance of <br> it finds
    index++;
}

Any ideas please?

Thanks in advance,

r3x
  • 2,125
  • 5
  • 23
  • 39
  • Well first, of all in the first iteration you will replace all the instances of `
    `.... To do it this way you would have to only replce parts of the string using `substr_replace` which lets you define the postions for he replacement.
    – prodigitalson Apr 22 '13 at 16:44

6 Answers6

8

I would use a regex and a custom callback, like this:

$str = "Line <br> Line <br> Line <br> Line <br>";
$replace = array("1", "2", "3", "4");
$str = preg_replace_callback( '/<br>/', function( $match) use( &$replace) {
    return array_shift( $replace) . ' ' . "\n";
}, $str);

Note that this assumes we can modify the $replace array. If that's not the case, you can keep a counter:

$str = "Line <br> Line <br> Line <br> Line <br>";
$replace = array("1", "2", "3", "4");
$count = 0;
$str = preg_replace_callback( '/<br>/', function( $match) use( $replace, &$count) {
    return $replace[$count++] . ' ' . "\n";
}, $str);

You can see from this demo that this outputs:

Line 1 Line 2 Line 3 Line 4 
nickb
  • 59,313
  • 13
  • 108
  • 143
  • You answer works and str is parsed correctly, but for some reason it is doesn't get inserted into the DB when I call INSERT INTO. Any ideas why? – r3x Apr 22 '13 at 17:15
  • @r3x - How come? Do you have an error message? If you're looking to print the literal `\n` characters instead of letting PHP interpret that to the newline character, change the double quotes around `"\n"` to single quotes. – nickb Apr 22 '13 at 17:18
  • Here is my insert query (interestTable is basically the parsed string). `mysql_query("INSERT INTO $tbl_name(userID,storyID,rank, storyType, interestTable)VALUES('$userID','$storyID','$rank','$storyType','$interestTable')", $dbh1);` If I delete the value of interestTable from this query then everything works fine, but if I add it nothing get sent. As for the error, I did not get any. Weird :S – r3x Apr 22 '13 at 17:23
  • I think that the string content is not formatted correctly. Even "Line 1 \nLine 2\nLine 3\nLine 4\n" are not inserted to the DB, so it is not a matter of size. – r3x Apr 22 '13 at 17:32
  • Without an error message or more information it's impossible to tell what's going wrong. – nickb Apr 22 '13 at 17:38
  • Turns out it's a format problem. (There was an `'` in the string.) Your code works fine :) – r3x Apr 23 '13 at 08:25
1
$str = str_replace('<br>', $replace[$index] . ' ' .'\n', $str);

This is replaces ALL the occurences of <br> it finds.

The correct is to only do one single replacement per iteration: substr_replace can replace one single part of a string. Correct would be:

while($pos = strpos($str, '<br>') !== false )
{
    $str = substr_replace($str, $replace[$replaceIndex] . ' ' .'\n', $pos, 4); // The <br> is four bytes long, so 4 bytes from $pos on.
    $replaceIndex++;
}

(Don't forget the $ before the replaceIndex! $replaceIndex is a variable)

bwoebi
  • 23,637
  • 5
  • 58
  • 79
  • 1
    The 4th parameter to `str_replace` is not how many times to replace. It's a reference that's set to how many time it *did* replace. – gen_Eric Apr 22 '13 at 16:52
1

if you just want to count it, you can use this too.

$str_expl = explode('<br>',$str);
foreach($str_expl as $index=>&$str)
    if(!empty($str))
        $str .= ($index+1);
$str = implode($str_expl);
ikkez
  • 2,052
  • 11
  • 20
  • if you want to replace the found items with your own array, you can change `str .= ($index+1)` to `str .= $myArray[index];` – ikkez Apr 22 '13 at 17:00
0

You need to remember the $ in front of variables. Also, try using the php regex function, which allows specifying the number of replacements.

<?php
$str     = "Line <br> Line <br> Line <br> Line <br>";
$replace = array("1", "2", "3", "4");
$index = 0;
$count = 1;

while(strpos($str, '<br>') != false )
{
    $str = preg_replace('/<br>/', $replace[$index] . " \n", $str, 1); //str_replace, replaces the first occurance of <br> it finds
    $index++;
}
echo $str
?>
Community
  • 1
  • 1
George
  • 367
  • 1
  • 10
  • The last parameter does not let you set the number of replacements. It's a reference that's set to the number of replacements it *did* do. – gen_Eric Apr 22 '13 at 16:54
  • I am referring to the $limit variable in [preg_replace](http://php.net/manual/en/function.preg-replace.php). – George Apr 22 '13 at 16:56
  • I thought you were using the `$count` parameter. Never mind :-) – gen_Eric Apr 22 '13 at 17:00
  • Ah, I see you were responding to the answer directly below mine! – George Apr 22 '13 at 17:05
  • This requires N regexes to be applied on the string, which can kill performance if the string contains a lot of `
    ` elements.
    – nickb Apr 22 '13 at 17:16
0

Here's my version. 8 formatted lines, no regex, KISS.

$str = "Line <br> Line <br> Line <br> Line <br>";
$replace = array("1", "2", "3", "4");

$temp = explode("<br>", $str);
$result = "";
foreach ($temp as $k=>$v) {
    $result .= $v;
    if ($k != count($temp) - 1) {
        $result .= $replace[$k];
    }
}

echo $result;
Ben
  • 54,723
  • 49
  • 178
  • 224
0

The preg_replace_callback will help you manipulate the replacement process, and nickb's answer shows how it can be done.

However, there can be more matches than the amount of items in the $replace array. If you want to re-start using its elements from the 0th item, you need to reset the counter once it is equal to the $replace array size.

See the PHP demo:

$text = "Line <br> Line <br> Line <br> Line <br> Line <br> Line <br>";
$replace = array("1", "2", "3", "4");
$counter = 0;
$text = preg_replace_callback('~<br\s*/?>~', function($m) use($replace, &$counter) {
    if ($counter === count($replace)) { $counter = 0; }
    return $replace[$counter++];
}, $text);
echo $text;

Output: Line 1 Line 2 Line 3 Line 4 Line 1 Line 2.

Note that the <br\s*/?> regex matches br tags that can be self-closing (/? matches an optional / char, and in order to keep / unescaped in the pattern, I used the ~ char as a regex delimiter) and that may contain zero or more whitespaces (\s*) after br and before /> / >.

Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563