Preg_replace only replaces first match - php

I'm relatively new to regex expressions and I'm having a problem with this one. I've searched this site and found nothing that works.
I want it to remove all <br /> between <div class='quote'> and </div>. The reason for this is that the whitespace is preserved anyway by the CSS and I want to remove any extra linebreaks the user puts into it.
For example, say I have this:
<div class='quote'>First line of text<br />
Second line of text<br />
Third line of text</div>
I've been trying to use this remove both the <br /> tags.
$TEXT = preg_replace("/(<div class='quote'>(.*?))<br \/>((.*?)<\/div>)/is","$1$3",$TEXT);
This works to an extent because the result is:
<div class='quote'>First line of text
Second line of text<br />
Third line of text</div>
However it won't remove the second <br />. Can someone help please? I figure it's probably something small I'm missing :)
Thanks!

If you want to clear all br-s inside only one div-block you need to first catch the content inside your div-block and then clear all your br-s.
Your regexp has the only one <br /> in it and so it replaces only one <br />.
You need something like that:
function clear_br($a)
{
return str_replace("<br />", "", $a[0]);
}
$TEXT = preg_replace_callback("/<div class='quote'>.*?<br \/>.*?<\/div>/is", "clear_br", $TEXT);

It does replace more than once, because you didn't use a 4th argument in preg_replace, so it is "without limit" and will replace more than once. It only replaced once because you specified the wrapping <div> in your regex and so it only matched your string once, because your string only has such a wrapping <div> once.
Assuming we already have:
<div class='quote'>First line of text<br />
Second line of text<br />
Third line of text</div>
we can simply do something like:
$s = "<div class='quote'>First line of text<br />\nSecond line of text<br>\nThird line of text</div>";
echo preg_replace("{<br\s*/?>}", " ", $s);
the \s* is for optional whitespaces, because what if it is <br/>? The /? is for optional / because it might be <br>. If the system entered those <br /> for you and you are sure they will be in this form, then you can use the simpler regex instead.
One word of caution is that I actually would replace it with a space, because for hello<br>world, if no space is used as the replacement text, then it would become helloworld and it merged two words into one.
(If you do not have this <div ... > ... </div> extracted already, then you probably would need to first do that using an HTML parser, say if the original content is a whole webpage (we use a parser because what if the content inside this outer <div>...</div> has <div> and </div> or even nested as well? If there isn't any <div> inside, then it is easier to extract it just using regex))

I don't get your [.*?] : You said here that you want "any charactere any number of times zero or one time". So you can simply say "any charactere any number of times" : .*
function clear_br($a){ return str_replace("<br />","",$a); }
$TEXT = preg_replace("/(<div class='quote'>.*<br \/>.*<\/div>)/",clear_br($1), $TEXT);
Otherwise that should works

You have to be careful about how you capture the div that contains the br elements. Mr. 動靜能量 pointed out that you need to watch out for nested divs. My solution does not.
<?php
$subject ="
<div>yomama</div>
<div class='quote'>First line of text<br />
Second line of text<br />
Third line of text</div>
<div>hasamustache</div>
";
$result = preg_replace_callback( '#<div[^>]+class.*quote.*?</div>#s',
function ($matches) {
print_r($matches);
return preg_replace('#<br ?/?>#', '', $matches[0]);
}
, $subject);
echo "$result\n";
?>
# is used as a regex delimiter instead of the conventional /
<div[^>]+ prevents the yomama div from being matched because it would have been with <div.*class.*quote since we have the s modifier (multiline-match).
quote.*? means a non-greedy match to prevent hasamustache</div> from being caught.
So the strategy is to match only the quote div in a string with newlines, and run a function on it that will kill all br tags.
output:

Related

replace text in single line after specific occurence using regex

I have searched for a solution to a problem on this site but have not found a way to do this task using regex (or perhaps something just shortened that uses less memory).
I am attempting to parse a string where text after a specific pattern (& the pattern itself) is to be removed from the same line. The text prior to to the pattern and also any line not containing the search pattern should be unedited.
Here is a working example:
$text = 'This is a test to remove single lines.<br />
The line below has the open type bbcode (case insensitive) that is to be removed.<br />
The text on the same line that follows the bbcode should also be removed.<br />
this text should remain[test]this text should be removed on this line only!<br />
the other lines should remain.<br />
done.<br />';
$remove = '[test]';
$lines = preg_split('/\r?\n/', $text);
foreach ($lines as $line)
{
$check = substr($line, 0, stripos($line, $remove));
$new[] = !empty($check) ? $check . '<br />' : $line;
}
$newText = implode($new);
echo $newText;
The above code works as expected but I would like to know how to do this using regex or perhaps something that uses a lot less code and memory. I have attempted to do this using regex from examples on this site + some tinkering but have not been able to get the result that is required. The solution should also use code that is compatible with PHP 5.5 syntax (no \e modifier). Using an array for the removal pattern will also be fitting as I may need to do a search for multiple patterns (although it is not shown in my example).
Thank you.
Thanks to frightangel for showing me the proper regex pattern.
Below is the necessary code to accomplish what was asked above:
$text = 'This is a test to remove single lines.<br />
The line below has the open type bbcode (case insensitive) that is to be removed.<br />
The text on the same line that follows the bbcode should also be removed.<br />
this text should remain[test]this text should be removed on this line only!<br />
the other lines should remain.<br />
[bbc]done.<br />
[another]this line should not be affected.<br />
it works!!<br />';
$removals = array('[test]', '[bbc]');
$remove = str_replace(array('[', ']'), array('~\[', '\].*?(?=\<br\s\/\>|\\n|\\r)~mi'), $removals);
$text = preg_replace($remove, '', $text);
echo $text;
The text that it searches for actually comes from a mysql query that feeds an array so I changed what is shown above to use what will more or less be used ($removals being that array).
The only problem left for me is that if text was prior to the removal then it would be better to leave the final line break from that line instead of omitting it. It should only be omitted if all text from a single line is removed.
Try this way:
$text = 'This is a test to remove single lines.<br />
The line below has the open type bbcode (case insensitive) that is to be removed.<br />
The text on the same line that follows the bbcode should also be removed.
this text should remain[test]this text should be removed on this line only!<br />
the other lines should remain.<br />
done.<br />';
$remove = 'test';
$text = preg_replace("/\[$remove\].*(?=\<br\s\/\>)/m", '', $text);
$text = preg_replace("/^(\<br\s\/\>)|(\\n)|(\\r)$/m","",$text);
echo $text;
Here's regex explanation: http://regex101.com/r/nW1bG8
try this, and tell me if thats what you want
if not, tell me, i probably didnt understand your question
preg_replace("/\[\S+\].+<[^>]+\s?\/>|<[^>]+\s?\/>/m","",$text);

SIMPLE HTML DOM - how to ignore nested elements?

My html code is as follows
<span class="phone">
i want this text
<span class="ignore-this-one">01234567890</span>
<span class="ignore-this-two" >01234567890</span>
<a class="also-ignore-me">some text</a>
</span>
What I want to do is extract the 'i want this text' leaving all of the other elements behind. I've tried several iterations of the following, but none return the text I need:
$name = trim($page->find('span[class!=ignore^] a[class!=also^] span[class=phone]',0)->innertext);
Some guidance would be appreciated as the simple_html_dom section on filters is quite bare.
what about using php preg_match (http://php.net/manual/en/function.preg-match.php)
try the below:
<?php
$html = <<<EOF
<span class="phone">
i want this text
<span class="ignore-this-one">01234567890</span>
<span class="ignore-this-two" >01234567890</span>
<a class="also-ignore-me">some text</a>
</span>;
EOF;
$result = preg_match('#class="phone".*\n(.*)#', $html, $matches);
echo $matches[1];
?>
regex explained:
find text class="phone" then proceed until the end of the line, matching any character using *.. Then switch to a new line with \n and grab everything on that line by enclosing *. into brackets.
The returned result is stored in the array $matches. $matches[0] holds the value that is returned from the whole regex, while $matches[1] holds the value that is return by the closing brackets.

remove line break after list items regex?

Okay i am looking for a way to have this:
<li>stuff</li><br />
Stripped of the ending
<br />
That gets added to it when i do a nl2br function in php.
Or do you think a better idea would be to strip all new lines inside
<ul>
tags?
This is part of a bbcode->html function for articles on my website.
Why not simply use str_replace?
$myString = str_replace('</li><br />', '</li>', $myString);
This removes all <br /> tags that follow a </li>.
Remove new lines from strings
As for removing br: str_replace br to empty string '' in your string

replace line break with 2 spans in php

Consider the following HTML string:
<p>This is line 1 <br /> and this is line 2</p>
How can i replace the above with the following string using PHP / Regex
<p><span class="single-line">This is line 1</span><span class="single-line">and this is line 2</span></p>
This works but I would advise you not to rely on regular expressions for HTML parsing / transformation:
$string = '<p>This is line 1 <br /> and this is line 2</p>';
$pattern = '~([^<>]+)<br[[:blank:]]*/?>([^<>]+)~i';
$replacement = '<span class="single-line">$1</span><span class="single-line">$2</span>';
echo preg_replace($pattern, $replacement, $string);
I do not really suggest that you actually do it (because IMHO you're misusing markup and classes), however it's actually pretty simple:
you replace
<p>
with
<p><span class="single-line">
and
<br />
with
</span><span class="single-line">
and finally
</p>
with
</span></p>
A PHP function that can replace strings is strtrDocs.
Note that this works only for exactly the HTML fragment you've given in your question. If you need this more precise, you should consider using DOMDocument and DOMXPath as I already commented above.

How to remove redundant <br /> tags from HTML code using PHP?

I'm parsing some messy HTML code with PHP in which there are some redundant tags and I would like to clean them up a bit. For instance:
<br>
<br /><br />
<br>
How would I replace something like that with this using preg_replace()?:
<br /><br />
Newlines, spaces, and the differences between <br>, <br/>, and <br /> would all have to be accounted for.
Edit: Basically I'd like to replace every instance of three or more successive breaks with just two.
Here is something you can use. The first line finds whenever there is 2 or more <br> tags (with whitespace between and different types) and replace them with wellformated <br /><br />.
I also included the second line to clean up the rest of the <br> tags if you want that too.
function clean($txt)
{
$txt=preg_replace("{(<br[\\s]*(>|\/>)\s*){2,}}i", "<br /><br />", $txt);
$txt=preg_replace("{(<br[\\s]*(>|\/>)\s*)}i", "<br />", $txt);
return $txt;
}
This should work, using minimum specifier:
preg_replace('/(<br[\s]?[\/]?>[\s]*){3,}/', '<br /><br />', $multibreaks);
Should match appalling <br><br /><br/><br> constructions too.
this will replace all breaks ... even if they're in uppercase:
preg_replace('/<br[^>]*>/i', '', $string);
Try with:
preg_replace('/<br\s*\/?>/', '', $inputString);
Use str_replace, its much better for simple replacement, and you can also pass an array instead of a single search value.
$newcode = str_replace("<br>", "", $messycode);

Categories