Jump to content

Function to add <p> tags


doubledee

Recommended Posts

I am tweaking a function which takes data that was entered into a Form TextArea and wraps each paragraph with <p></p> tags so things are properly marked up.

 

It seems to be working okay, except for two annoying things...

 

1.) When I go to View ---> Source, I do NOT want to see paragraph after paragraph all on the same line.

 

I tried adding a \n into the preg_replace but it is adding an extra carriage return in the output.

 

 

2.) Right now, if my code sees 2 \n's it will convert that to "</ p><p>", which is fine.  However it does the same thing if there are 20 \n's which is technically wrong, because maybe someone wanted the extra 18 carriage returns between their paragraphs?!

 

For example, in the line below "I decided to start..." that line should get wrapped in <p></p> and then there should be a <br /><br /> because the User added two *extra* carriage returns, and then the next line "My boss is a jerk..." should get wrapped in <p></p> because it is also a paragraph.

 

I'm sure this one is impossible to do, but the end goal is simple...

 

Regardless of how many carriage returns there are between blocks of text, the blocks of text should first get wrapped in <p> </p> but then any additional line spacing should be preserved.

 

Hope that makes sense?!

 

Here is the code I am working with...

$text="I decided to start my own business because I want to be my own boss!



My boss is a jerk and never appreciates anything that I do for him, so why put up with the abuse?!  He takes me for granted and doesn't appreciate all of my talents.

Running my own business will give me a chance to do things as I see fit...

Line One
Line Two
Line Three
Line Four



Line Eight";


$text2 = htmlentities($text, ENT_QUOTES);


function nl2p($string, $line_breaks = true) {
// Remove existing HTML formatting to avoid double tags.
//^	$string = str_replace(array('<p>', '</p>', '<br>', '<br/>'), '', $string);

// Replace Carriage Return with Empty String.
// Replace multiple Newlines with closing & opening paragraph tags.
// Replace single Newline with break tag.
if ($line_breaks == true) {
	return '<p>'.preg_replace(array("#\r#","#\n{2,}#", "#\n#"), array("","</p><p>", "<br />\n"), $string).'</p>';
}else{
	return '<p>'.preg_replace("#\n#", "</p><p>", trim($string)).'</p>';
}
}

echo nl2p($text2, TRUE);

 

Oh, btw, as you can see, adding a \n after the line break (i.e. "<br />\n") actually added the line break in my Source as I wanted.  It is just when you add a \n in between the paragraphs that my code misbehaves (i.e. "</p>\n<p>").

 

Can these two problems be fixed??  :shrug:

 

Thanks,

 

 

Debbie

 

Link to comment
Share on other sites

Here is my best stab at things, with the part in Red being where I am stuck...

 

return '<p>'.preg_replace(array("#\r#", "#\n{2}#", "#\n{3,}#", "#\n#"), array("", "</p><p>", "</p>insert extra breaks here<p>", "<br />\n"), $string).'</p>';

 

Maybe this is too fancy for my preg_replace, but hey, we can dream, right?!  *LOL*

 

Thanks,

 

 

Debbie

 

Link to comment
Share on other sites

Why does the source code need to be pretty? Most mark-up debuggers will display the DOM in a tree-view for you, and these come with or are plugged directly in to the browser.

 

It's going to be a bunch of extra work to keep 'pretty' as you have to keep track of base indentation, word-wrap, etc.

 

Here's a basic snippet that deals with the linebreaks

<?php

$string = 'A bunch of text
A new paragraph

With an extra line break




And a bunch more';

# Convert Windows (\r\n) and Mac (\r) to Unix (\n)
$string = str_replace(array("\r\n","\r"), "\n", $string);

# Grab a linebreak, followed by 0 or more linebreaks afterwards
$string = preg_replace_callback('#\n(\n*)#',
# Using unlgy create function, in case 5.3 not available
create_function('$match',
	# Start a new paragraph
	'$return = "</p>\n";'.
	# Check if our capturing group found any extra linebreaks, and replace those with BRs
	'if( !empty($match[1]) ) $return .= str_replace("\n","<br>",$match[1])."\n";'.
	# Return
	'return $return."<p>";'
),
$string
);

echo '<p>'.$string.'</p>';

?>

 

The create_function syntax is ugly, but it works pre 5.3, and is better than cluttering your namespace with a one-use function IMO.

 

Produces

<p>A bunch of text</p>
<p>A new paragraph</p>
<br>
<p>With an extra line break</p>
<br><br><br><br>
<p>And a bunch more</p>

 

Link to comment
Share on other sites

Why does the source code need to be pretty? Most mark-up debuggers will display the DOM in a tree-view for you, and these come with or are plugged directly in to the browser.

 

I don't, but I just like pretty code for readability.

 

 

It's going to be a bunch of extra work to keep 'pretty' as you have to keep track of base indentation, word-wrap, etc.

 

I was just hoping to have each <p> on its on line in the Source versus everything on one enormously long line.

 

 

Here's a basic snippet that deals with the linebreaks

<?php

$string = 'A bunch of text
A new paragraph

With an extra line break




And a bunch more';

# Convert Windows (\r\n) and Mac (\r) to Unix (\n)
$string = str_replace(array("\r\n","\r"), "\n", $string);

# Grab a linebreak, followed by 0 or more linebreaks afterwards
$string = preg_replace_callback('#\n(\n*)#',
# Using unlgy create function, in case 5.3 not available
create_function('$match',
	# Start a new paragraph
	'$return = "</p>\n";'.
	# Check if our capturing group found any extra linebreaks, and replace those with BRs
	'if( !empty($match[1]) ) $return .= str_replace("\n","<br>",$match[1])."\n";'.
	# Return
	'return $return."<p>";'
),
$string
);

echo '<p>'.$string.'</p>';

?>

 

The create_function syntax is ugly, but it works pre 5.3, and is better than cluttering your namespace with a one-use function IMO.

 

Produces

<p>A bunch of text</p>
<p>A new paragraph</p>
<br>
<p>With an extra line break</p>
<br><br><br><br>
<p>And a bunch more</p>

 

That is some pretty fancy coding there!!!  8)

 

It works pretty well, except that if you have two lines separated by just a carriage return, they are showing up wrapped in paragraph tags.

 

For instance...

Line 1

Line 2

 

Is showing up in code as...

<p>Line 1</p>

<p>Line 2</p>

 

And outputting as...

Line 1

 

Line 2

 

When the code should actually be...

<p>Line 1<br />

Line 2</p>

 

And the output should be...

Line 1

Line 2

 

 

I have some questions on you code, but I'll let you respond to my comments first in case things change?!

 

 

BTW, here is my best guess at things...

$text="I decided to start my own business because I want to be my own boss!



My boss is a jerk and never appreciates anything that I do for him, so why put up with the abuse?!  He takes me for granted and doesn't appreciate all of my talents.

Running my own business will give me a chance to do things as I see fit...

Line One
Line Two
Line Three
Line Four



Line Eight

Line Ten";


$text2 = htmlentities($text, ENT_QUOTES);


function nl2p($string, $line_breaks = true) {
// Remove existing HTML formatting to avoid double tags.
//^	$string = str_replace(array('<p>', '</p>', '<br>', '<br/>'), '', $string);

// Replace Carriage Return with Empty String.
// Replace multiple Newlines with closing & opening paragraph tags.
// Replace single Newline with break tag.
if ($line_breaks == true) {
	return '<p>'.preg_replace(array("#\r#", "#\n{3,}#", "#\n{2}#", "#\n#"), array("", "</p><br /><p>", "</p><p>", "<br />\n"), $string).'</p>';
//		return '<p>'.preg_replace(array("#\r#","#\n{2,}#", "#\n#"), array("","</p><p>", "<br />\n"), $string).'</p>';
}else{
	return '<p>'.preg_replace("#\n#", "</p><p>", trim($string)).'</p>';
}
}

echo nl2p($text2, TRUE);

 

My code is almost perfect, except if you have 10 carriage returns between two paragraphs, you just get one fixed break <br /> between them since I didn't know how to do a callback or whatever is needed.

 

I can live with my code as-is, but if I could fix this one last thing I suppose it would be nice...

 

Where I use my code and fix this one last thing, or use your code above and address the issues noted makes no difference to me.

 

Thanks for the help!!!

 

 

Debbie

 

P.S.  You code does a much "prettier" job in the View--> Source  :)

 

 

 

Link to comment
Share on other sites

You don't actually need all of those paragraph tags for proper markup.

 

I do need properly placed <p> tags in order to style things like I want...

 

 

Debbie

 

 

How do you want to style it?

 

I'm confident you can achieve it using CSS which is a lot less effort.

Link to comment
Share on other sites

You don't actually need all of those paragraph tags for proper markup.

 

I do need properly placed <p> tags in order to style things like I want...

 

 

Debbie

 

 

How do you want to style it?

 

I'm confident you can achieve it using CSS which is a lot less effort.

 

I appreciate your eagerness for an easier way, but that isn't what I want...

 

Just like when I hand-code a webpage, paragraphs need to be wrapped in <p></p> tags.  Sentences - within a paragraph - that need extra lines between them are separated by line breaks <br />.

 

Why in the world content typed into an HTML TextArea doesn't come out that way on it's own is besides me, but I want things in that format 1.) Because that is proper semantic markup, and 2.) Because I need <p> tags as hooks for my already established styles.

 

But I don't want to start a debate on that...

 

 

The code I posted above is basically good enough for my needs, and it marks up the text properly.

 

And Xyph's attempt is equally close.

 

I was just hoping to get that last 10% right in either my version or Xyph's version...

 

 

Debbie

 

Link to comment
Share on other sites

Just thought I'd see what the big boys have to say about the example I offered.

<?php
$text="I decided to start my own business because I want
to be my own boss!

My boss is a jerk and never appreciates anything
that I do for him, so why put up with the abuse?!
He takes me for granted and doesn't appreciate
all of my talents.

Running my own business will give me a chance
to do things as I see fit...";

function nl2p($text) {
$text=str_replace("\n\r\n","</p>\r\r<p>","$text");
$text=str_replace("\n","<br /> ","$text");
$text="<p>" . $text . "</p>";
return($text); 
}
echo nl2p($text);
?>

Link to comment
Share on other sites

Drummin,

 

Nice try, but you code doesn't wrap a <p></p> around each paragraph...

 

It just adds <br /> where there is a carriage return.

 

nl2br() does that out-of-the-box.

 

I think what I have or Xyph proposed seems to be closest and worth tweaking...

 

 

Debbie

 

Link to comment
Share on other sites

my 0.02 worth

 

function paras($text)
{
    function nl(&$v, $k)
    {
        $v = nl2br($v);
    }
        
    $a = explode("\n\n", $text);
    array_walk($a, 'nl');
    return '<p>' . join("</p>\n\n<p>", $a) . '</p>';
}

echo paras($text);

Link to comment
Share on other sites

my 0.02 worth

 

function paras($text)
{
    function nl(&$v, $k)
    {
        $v = nl2br($v);
    }
        
    $a = explode("\n\n", $text);
    array_walk($a, 'nl');
    return '<p>' . join("</p>\n\n<p>", $a) . '</p>';
}

echo paras($text);

 

That doesn't even run...

 

 

Debbie

 

Link to comment
Share on other sites

Drummin,

 

Nice try, but you code doesn't wrap a <p></p> around each paragraph...

 

It just adds <br /> where there is a carriage return.

 

nl2br() does that out-of-the-box.

 

I think what I have or Xyph proposed seems to be closest and worth tweaking...

 

 

Debbie

If possible, can some then please explain why I get single line breaks as <br /> and double breaks with <p></p> as shown below but Debbie does not.  Is it a doctype issue?  Server issue?  Something else?

<html>
<body>
<p>I decided to start my own business because I want
<br /> to be my own boss!
</p>

<p>My boss is a jerk and never appreciates anything
<br /> that I do for him, so why put up with the abuse?!
<br /> He takes me for granted and doesn't appreciate
<br /> all of my talents.
</p>

<p>Running my own business will give me a chance
<br /> to do things as I see fit...</p></body>
</html>

Link to comment
Share on other sites

That doesn't even run...

 

Should do. I ran it before posting and got this result:

 

<p>I decided to start my own business because I want to be my own boss!</p>

<p>My boss is a jerk and never appreciates anything that I do for him, so why put up with the abuse?!  </p>

<p>He takes me for granted and doesn't appreciate all of my talents.Running my own business will give me a chance to do things as I see fit...</p>

<p></p>

<p>Line One<br />
Line Two<br />
Line Three<br />
Line Four</p>

<p></p>

<p>Line Eight</p>

Link to comment
Share on other sites

Hmm

My code gives me

<p>I decided to start my own business because I want
<br /> to be my own boss!
</p>

<p>My boss is a jerk and never appreciates anything
<br /> that I do for him, so why put up with the abuse?!
<br /> He takes me for granted and doesn't appreciate
<br /> all of my talents.
</p>

<p>Running my own business will give me a chance
<br /> to do things as I see fit...</p>

 

Barand's code give me

<p>I decided to start my own business because I want<br />
to be my own boss!<br />
<br />
My boss is a jerk and never appreciates anything<br />
that I do for him, so why put up with the abuse?!<br />
He takes me for granted and doesn't appreciate<br />
all of my talents.<br />
<br />
Running my own business will give me a chance<br />
to do things as I see fit...</p>

Link to comment
Share on other sites

Mine's easy enough to change, just add a second capturing group. This one's PHP 5.3+, as I've already shown an example with create_function, and I hate programming in strings.

 

<?php

$string = 'A bunch of text
The same paragraph

A new paragraph




New one with linebreaks in between';

# Convert Windows (\r\n) and Mac (\r) to Unix (\n)
$string = str_replace(array("\r\n","\r"), "\n", $string);

# Grab a linebreak, followed by 0 or 1 linebreak after, followed by 0 or more after that
$string = preg_replace_callback('#\n(\n?)(\n*)#',
function( $match ) {
	$return = '';
	# Only 1 line break matched
	if( empty($match[1]) && empty($match[2]) ) return "<br>\n";
	# At least 2 matched
	else $return .= "</p>\n";
	# More than 2 matched
	if( !empty($match[2]) ) $return .= str_replace("\n","<br>\n",$match[2]);
	return $return.'<p>';
},
$string
);

echo '<p>'.$string.'</p>';

?>

 

In the future, you should try to make the changes to work yourself, and if you can't, ask for more help. As it is, it looks like you're just waiting for someone to post a completely working solution. Replies like this:

That doesn't even run...

are unacceptable if you want people to help you further.

 

Try it, if it fails, post the code you've tried and the reason you tried it.

Link to comment
Share on other sites

Mine's easy enough to change, just add a second capturing group. This one's PHP 5.3+, as I've already shown an example with create_function, and I hate programming in strings.

 

<?php

$string = 'A bunch of text
The same paragraph

A new paragraph




New one with linebreaks in between';

# Convert Windows (\r\n) and Mac (\r) to Unix (\n)
$string = str_replace(array("\r\n","\r"), "\n", $string);

# Grab a linebreak, followed by 0 or 1 linebreak after, followed by 0 or more after that
$string = preg_replace_callback('#\n(\n?)(\n*)#',
function( $match ) {
	$return = '';
	# Only 1 line break matched
	if( empty($match[1]) && empty($match[2]) ) return "<br>\n";
	# At least 2 matched
	else $return .= "</p>\n";
	# More than 2 matched
	if( !empty($match[2]) ) $return .= str_replace("\n","<br>\n",$match[2]);
	return $return.'<p>';
},
$string
);

echo '<p>'.$string.'</p>';

?>

 

Is there a way to make that work in versions earlier than PHP 5.3??  (I'm on MAMP and am stuck with 5.2.6)

 

 

In the future, you should try to make the changes to work yourself, and if you can't, ask for more help. As it is, it looks like you're just waiting for someone to post a completely working solution. Replies like this:

That doesn't even run...

are unacceptable if you want people to help you further.

 

Try it, if it fails, post the code you've tried and the reason you tried it.

 

I did run his code and that is why I posted that.  (Turns out I had some parse error I didn't catch.)

 

 

Debbie

Link to comment
Share on other sites

I did run his code and that is why I posted that.  (Turns out I had some parse error I didn't catch.)

 

Then mention the parse error, post the code that caused the error, etc. Statements like the one I quoted aren't going to help anyone with anything.

 

Is there a way to make that work in versions earlier than PHP 5.3??  (I'm on MAMP and am stuck with 5.2.6)

 

Yes, there are two ways. I mentioned one in my first reply, and gave a direct example using the other in my first snippet.

 

You can use the create_function syntax, or you can hard-code the function outside of the preg_replace_callback arguments, and include the function name, as a string, in it's place.

Link to comment
Share on other sites

I did run his code and that is why I posted that.  (Turns out I had some parse error I didn't catch.)

 

That's OK, Doubledee. Apology accepted.

 

Glad someone did!

 

I think we have too many version going on for one thread...

 

FWIW, here is your code with my test data...

<?php

$text="I decided to start my own business because I want to be my own boss!



My boss is a jerk and never appreciates anything that I do for him, so why put up with the abuse?!  He takes me for granted and doesn't appreciate all of my talents.

Running my own business will give me a chance to do things as I see fit...

Line One
Line Two
Line Three
Line Four



Line Eight

Line Ten";


function paras($text)
{
    function nl(&$v, $k)
    {
        $v = nl2br($v);
    }

    $a = explode("\n\n", $text);
    array_walk($a, 'nl');
    return '<p>' . join("</p>\n\n<p>", $a) . '</p>';
}

echo paras($text);

?>

 

When I run your code I see this output...

I decided to start my own business because I want to be my own boss!

 

My boss is a jerk and never appreciates anything that I do for him, so why put up with the abuse?! He takes me for granted and doesn't appreciate all of my talents.

 

Running my own business will give me a chance to do things as I see fit...

 

Line One

Line Two

Line Three

Line Four

 

Line Eight

 

Line Ten

 

Notice how we lost two lines at the top...

 

 

Furthermore, if we look at the HTML, you see an errant <p></p> after the first line with nothing in it.

<p>I decided to start my own business because I want to be my own boss!</p>

 

<p></p>

 

<p>My boss is a jerk and never appreciates anything that I do for him, so why put up with the abuse?!  He takes me for granted and doesn't appreciate all of my talents.</p>

 

<p>Running my own business will give me a chance to do things as I see fit...</p>

 

<p>Line One<br />

Line Two<br />

Line Three<br />

Line Four</p>

 

<p></p>

 

<p>Line Eight</p>

 

<p>Line Ten</p>

 

 

The above test data is NOT the best choice to show what I am looking for, however based on my rules, it should have this HTML...

<p>I decided to start my own business because I want to be my own boss!</p>

<br />

<br />

<br />

<p>My boss is a jerk and never appreciates anything that I do for him, so why put up with the abuse?!  He takes me for granted and doesn't appreciate all of my talents.</p>

<br />

<p>Running my own business will give me a chance to do things as I see fit...</p>

<br />

<p>Line One<br />

Line Two<br />

Line Three<br />

Line Four</p>

<br />

<br />

<br />

<p>Line Eight</p>

<br />

<p>Line Ten</p>

 

 

Without being a human, this is virtually no way to know how to properly determine what is a Paragraph and what isn't in the disparate example above.  However, this is what I was trying to do...

 

- If you have a sentence/phrase/block of text, and it is followed by two carriage returns, then it should be wrapped in <p></p>

- If you have a sentence/phrase/block of text, and it is followed by one carriage returns, then it should be followed by a <br />

 

So a better example would be...

<p>This is one sentence in our paragraph.  This is another sentence in our paragraph.  And so on...</p>

 

<p>This is yet another paragraph but with only one sentence...</p>

 

<p>This is a list...<br />

Item 1<br />

Item 2<br />

Item 3 (End with a P-tag)<br /></p>

<br />

<br />

<br />

<p>This is a new paragraph.  It has no space after this line, so we need a break.<br />

This is still part of the same paragraph because we don't have a blank line in between...<br />

Still the same paragraph but this time we close it out.</p>

<br />

<p>The end.</p>

 

That oughta keep ya busy!!

 

 

Debbie

 

P.S.  I still think Xyph's example has the most hope, but this thread is rather *foggy* at this point?!  8)

 

 

Link to comment
Share on other sites

This is the method I generally use for wrapping paragraphs. Hope this helps.

function wrapBody($body){
    $temp = '';
    $lines = explode("\r\n", $body);
    foreach($lines as $line){
        if(!empty($line)){
            $temp .= "<p>".$line."</p>\n";
        }
    }
    return $temp;
}

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.