13

I'm developing a single serving site in PHP that simply displays messages that are posted by visitors (ideally surrounding the topic of the website). Anyone can post up to three messages an hour.

Since the website will only be one page, I'd like to control the vertical length of each message. However, I do want to at least partially preserve line breaks in the original message. A compromise would be to allow for two line breaks, but if there are more than two, then replace them with a total of two line breaks in a row. Stack Overflow implements this.

For example:

Porcupines\nare\n\n\n\nporcupiney.

would be changed to

Porcupines<br />are<br /><br />porcupiney.

One tricky aspect of checking for line breaks is the possibility of their being collected and stored as \r\n, \r, or \n. I thought about converting all line breaks to <br />s using nl2br(), but that seemed unnecessary.

My question: Using regular expressions in PHP (with functions like preg_match() and preg_replace()), how can I check for instances of more than two line breaks in a row (with or without blank space between them) and then change them to a total of two line breaks?

mickmackusa
  • 43,625
  • 12
  • 83
  • 136
tevan
  • 133
  • 1
  • 1
  • 6

4 Answers4

34
preg_replace('/(?:(?:\r\n|\r|\n)\s*){2}/s', "\n\n", $text)
chaos
  • 122,029
  • 33
  • 303
  • 309
  • Original response didn't meet your 'with or without blank space between them' criterion. :) – chaos May 03 '09 at 05:19
  • But when there's only one line break, it changes it to two? Shouldn't it leave a single break as it is? – NonCoder May 15 '15 at 00:09
  • This preg will not match a single line break. The `{2}` limits matches to two. – Quinn Comendant Jun 21 '15 at 20:53
  • @QuinnComendant: Yes. That is part of the requested behavior. – chaos Jul 09 '15 at 04:44
  • @chaos Thank you for this solution! When I used it, single linebreaks where always turned into two linebreaks. I had to change the `*` into a `+` to stop replacing single linebreaks: `preg_replace('/(?:(?:\r\n|\r|\n)\s*){2}/s', "\n\n", $text)` – arkuuu Aug 29 '17 at 09:30
6

Something like

preg_replace('/(\r|\n|\r\n){2,}/', '<br/><br/>', $text);

should work, I think. Though I don't remember PHP syntax exactly, it might need some more escaping :-/

David Z
  • 128,184
  • 27
  • 255
  • 279
  • Thanks David. The only issue I see with the regular expression you posted is that it doesn't accommodate spaces between line breaks. – tevan May 03 '09 at 02:53
  • Ah, true... I missed the part of your question where you mentioned spaces between line breaks. – David Z May 03 '09 at 03:21
1

\R is the system-agnostic escape sequence which will match \n, \r and \r\n.

Because you want to greedily match 1 or 2 consecutive newlines, you will need to use a limiting quantifier {1,2}.

Code: (Demo)

$string = "Porcupines\nare\n\n\n\nporcupiney.";

echo preg_replace('~\R{1,2}~', '<br />', $string);

Output:

Porcupines<br >are<br /><br />porcupiney.

Now, to clarify why/where the other answers are incorrect...

@DavidZ's unexplained answer fails to replace the lone newline character (Demo of failure) because of the incorrect quantifier expression.

It generates:

Porcupines\nare<br/><br/>porcupiney.

The exact same result can be generated by @chaos's code-only answer (Demo of failure). Not only is the regular expression long-winded and incorrectly implementing the quantifier logic, it is also adding the s pattern modifier.

The s pattern modifier only has an effect on the regular expression if there is a dot metacharacter in the pattern. Because there is no . in the pattern, the modifier is useless and is teaching researchers meaningless/incorrect coding practices.

mickmackusa
  • 43,625
  • 12
  • 83
  • 136
0

I just wanted to add to this, even though it doesnt directly answer the question, it may help someone who is wanting to limit the number of line breaks. I needed this to limit the number of line breaks in forum posts. I used the selected answer above, and added this:

//Some pre processing
$textarea_reply = str_replace("\r", "<br>", $textarea_reply);
$textarea_reply_splitByLines = explode("<br>", $textarea_reply);
$textarea_reply = "";
$line_count = 0;
$line_limit = 10;

//Re-add the line breaks with a limit of $line_limit
foreach ($textarea_reply_splitByLines as $line){
    $textarea_reply.= $line." "; 
    if($line_count<$line_limit) $textarea_reply.= "<br>";
    $line_count++;
}

This limits the number of line breaks to a maximum amount no matter what.

SW_Cali
  • 383
  • 2
  • 17