I need some help with PHP please (preg_match_all)
I need some help with PHP please (preg_match_all)
Author
Discussion

TonyRPH

Original Poster:

13,546 posts

198 months

Friday 30th April 2021
quotequote all
I have a custom function which adds a <br /> to text.

However, I want it to ignore more than just the single <table> tag I have here.

I have tried preg_match_all using "/<pre><code><table>(.*?)\</code></pre></table>/s" as my string to match with a foreach loop but I just can't seem to get it to work.

I just keep getting warnings: "PHP Notice: Array to string conversion"

Can anybody help please?

Below is my working code:

working code said:
function custom_nl2br($html) {
$pattern = "/<table>(.*?)<\/table>/s";
preg_match($pattern, $html, $matches);

$html = nl2br(str_replace($matches[0], '[placeholder]', $html));
$html = str_replace('[placeholder]',$matches[0], $html);

return $html;
}
code I have tried said:
function custom_nl2br($html) {
$pattern = "/<pre><code><table>(.*?)\</code></pre></table>/s";
preg_match_all($pattern, $html, $matches);

foreach($matches[1] as $a) {
$html = str_replace($a, str_replace("<br />", '', $a), $html);
}
return $html;
}

mikef

6,158 posts

281 months

Friday 30th April 2021
quotequote all
Try

/<pre><code><table>(.*?)<\/table><\/code><\/pre>/s

TonyRPH

Original Poster:

13,546 posts

198 months

Friday 30th April 2021
quotequote all
Thanks - but still no match - $a remains empty if I try and dump it out with print_r($a) or var_dump($a) / echo($a)


I just tried to post the revised code and I get a "403 forbidden" <sighs>



mikef

6,158 posts

281 months

Saturday 1st May 2021
quotequote all
Show us the test data?

TonyRPH

Original Poster:

13,546 posts

198 months

Saturday 1st May 2021
quotequote all
It's largely plain text being read from the database, with some html content.

It looks like this sample:


<h1>This is a test</h1>

This is some test text.
And a second line.
And a third line.

<pre>
This is some preformatted text.
With another line.
And another line.
</pre>

<table>
<tr><td>column</td></tr>
<tr><td>column2</td></tr>
<tr><td>columns3</td></tr>
</table>



What I'm trying to achieve, is to prevent a <br /> tag being appended to lines between html tags, and only appended to plain text.

I can do it with one set of tags (using the code above) but I want to look through the entire dataset and ensure nothing is added between tags.

I have tested my regex and it does seem to work - but I suspect it's the foreach loop that's not working properly.


mikef

6,158 posts

281 months

Saturday 1st May 2021
quotequote all
So you're looking for <pre> OR <code> OR <table>, not embedded tags?

Wouldn't that be
/(<pre>|<code>|<table>)(.*?)(<\/table>|<\/code>|<\/pre>)/sg
?



Edited to post screenshot from regex101 that shows what the regex is doing

Edited by mikef on Saturday 1st May 16:59

TonyRPH

Original Poster:

13,546 posts

198 months

Saturday 1st May 2021
quotequote all
mikef said:
So you're looking for <pre> OR <code> OR <table>, not embedded tags?

Wouldn't that be

(<pre>|<code>|<table>)(.*?)(<\/table>|<\/code>|<\/pre>)

?
Yes I think you could be right - although all the example I found on Stackoverflow etc. suggest that the regex should just contain the fields are I posted previously.

I shall try your suggestion, thanks.


Mr Happy

5,897 posts

250 months

Saturday 1st May 2021
quotequote all
TonyRPH said:
mikef said:
So you're looking for <pre> OR <code> OR <table>, not embedded tags?

Wouldn't that be

(<pre>|<code>|<table>)(.*?)(<\/table>|<\/code>|<\/pre>)

?
Yes I think you could be right - although all the example I found on Stackoverflow etc. suggest that the regex should just contain the fields are I posted previously.

I shall try your suggestion, thanks.
Its been a while since I dabbled in regex, but be careful with this as if I've understood it - there's no guarantee that the opening token is matched with its closing token. If you have a table with pre tags within, you could end up with your regex matching your starting table tag and the ending pre tag.

You'd be better off having three distinct regexes matching the pre, table and code tags and their respective end tags imo. I don't think there'd be that much of a performance hit unless you're regexing across loads of text.

mikef

6,158 posts

281 months

Saturday 1st May 2021
quotequote all
True, if writing a generalised utility (and even then, malformed html may work without a closing tag)

I assumed the OP was working with a known dataset

TonyRPH

Original Poster:

13,546 posts

198 months

Saturday 1st May 2021
quotequote all
mikef said:
<snip>

I assumed the OP was working with a known dataset
You assumed correctly.

The html is consistent and minimal. There will always be matching tags with no 'rogue' tags in between.



Mr Happy

5,897 posts

250 months

Sunday 2nd May 2021
quotequote all
I was coming into it from the perspective of my day job! Just because the dataset is sane now doesn't mean it'll always be so...

It never hurts to build in a bit of resilience when you can!

TonyRPH

Original Poster:

13,546 posts

198 months

Sunday 2nd May 2021
quotequote all
Mr Happy said:
I was coming into it from the perspective of my day job! Just because the dataset is sane now doesn't mean it'll always be so...

It never hurts to build in a bit of resilience when you can!
I agree - however in this case it just needs to work and that's all.


TonyRPH

Original Poster:

13,546 posts

198 months

Tuesday 4th May 2021
quotequote all
Just to update this.

I got it around it with CSS instead.

I created a new class and wrapped the text I don't want any <br /> tags with this new class, that simply 'hides' the <br /> (using display: none) from the browser and hence is not rendered.

I also added "content: \a" and "white-space: pre" tags which inserts a line break without the <br />.

CSS said:
.scripts-bg {
background-color: gainsboro;
font-family: monospace;
padding: 10px;
content: "\a";
white-space: pre;
}

.scripts-bg br {
display: none;
}