7

I'm trying to code a regexp to convert a block of text:

* List item
* Another list item

to html:

<ul>
    <li>List item</li>
    <li>Another list item</li>
</ul>

I know there are snippets or classes to do this (Markdown, Textile, etc) but I think it's overkill: I really just want some basic functionality. So far I'm trying with:

$text = preg_replace("/\*+(.*)?/i","<li>$1</li>",$text);

But I don't know how to wrap everything in <ul> tags without using a separate replace, like so:

$text = preg_replace("/(\<li\>(.*)\<\/li\>\n*)+/is","<ul>\n$1\n</ul>\n",$text);

This interferes with other code, for example ordered lists. There must be a better way.

Thanks.

Alan Moore
  • 73,866
  • 12
  • 100
  • 156
Reven
  • 173
  • 1
  • 4

4 Answers4

14

On this question, if you where talking about the fact that the code you used would wrap multiple sets of li tags in one ul tag even if there was suppose to be a break in there like so:

* line 1
* line 1
* line 1
this is not part of a list
* line 1
* line 1
* line 1

Would become:

<ul>
<li>line 1</li>
<li>line 1</li>
<li>line 1</li>
this is not part a the list
<li>line 1</li>
<li>line 1</li>
</ul>

Then I have a solution for you. You had 90% of it there, here is a solution I came up with (but I am sure you already solved it anyway):

$text = preg_replace("/\*+(.*)?/i","<ul><li>$1</li></ul>",$text);
$text = preg_replace("/(\<\/ul\>\n(.*)\<ul\>*)+/","",$text);

The solution does not mess with lists of any kind already on the page in the text or whatever and makes sure to separate multiple lists. Reason is that every match it finds where an asterisk was used to create a text list item it surrounds that with a ul and li then the 2nd line finds all of the back to back closing and opening ul tags and removes them.

BrandonS
  • 932
  • 7
  • 16
  • That's quite ingenious! And it would solve the problem. Thank you. I'll give it a RealWorld® spin and see how it works. – Reven Sep 27 '11 at 14:51
  • 2
    The above regex gives problems when * appears in the middle of a phrase. If you run into that problem, then you can modify the regex to only match * when it's at the beginning of a line: preg_replace("/^*+(.*)?/im","
    • $1
    ",$text);
    – bart Jan 18 '15 at 00:36
1

Why don't you store the first regex in an array with preg_match_all, and glue it like this:

$list='<ul><li>';
$list .= implode('</li><li>',$arr_regex);
$list .= '</li></ul>';
DCC
  • 249
  • 1
  • 5
  • That would work if the text was the only element in the block of text, but there are things before and after. –  Feb 27 '10 at 02:01
0

Well, you could simply do

$text = "<ul>" . preg_replace("/\*+(.*)?/i","<li>$1</li>",$text) . "</ul>";

or, if you really want to use preg_replace

$text = preg_replace("/(\<li\>(.*?)\<\/li\>\n*)+/is","<ul>\n$1\n</ul>\n",$text);
Paulo Santos
  • 11,285
  • 4
  • 39
  • 65
  • Again, maybe I didn't make this clear (sorry), but there are more things in $text, so adding
      won't work.
    –  Feb 27 '10 at 02:03
0

Perhaps you may find PHP Markdown useful.

Ignacio Vazquez-Abrams
  • 776,304
  • 153
  • 1,341
  • 1,358
  • Was kind of trying to avoid using it, to be honest. Just need a couple of substitutions. My script is about 10Kb. Including a 40Kb script just to do that seems overkill. –  Feb 27 '10 at 02:04