Apply PHP regex on multiline re-pattern
Let's say I have this input:
I can haz a listz0rs!
# 42
# 126
I can haz another list plox?
# Hello, world!
# Welcome!
I want to split it up so that each set of hash-started strings becomes a list:
I can haz a listz0rs!
<ul>
<li>42</li>
<li>126</li>
</ul>
I can haz another list plox?
<ul>
<li>Hello, world!</li>
<li>Welcome!</li>
</ul>
If I run the regex input "/ (?: (?: (? <= ^ #) (. *) $) +) / M", I get the following output:
Array
(
[0] => Array
(
[0] => 42
)
[1] => Array
(
[0] => 126
)
[2] => Array
(
[0] => Hello, world!
)
[3] => Array
(
[0] => Welcome!
)
)
It's fine and dandy, but it doesn't distinguish between two different lists. I need a way to make the quantifier return a concatenated string of all occurrences, or ideally an array of all occurrences.
Ideally, this should be my conclusion:
Array
(
[0] => Array
(
[0] => 42
[1] => 126
)
[1] => Array
(
[0] => Hello, world!
[1] => Welcome!
)
)
Is there a way to achieve this, and if not, is there a close alternative?
a source to share
If you want to do this with regular expressions, you need two. Use regex ^(#.*\r?\n)+
to match each list and add tags to it. Within each list (according to the first regex), search and replace ^#.*
with <li>$0</li>
to add tags around each list item. Both regex require ^
line breaks to match (flag /m
in PHP).
In PHP, you can use preg_replace_callback
and preg_replace
to achieve this with just a few lines of code.
$result = preg_replace_callback('/^(#.*\r?\n)+/m', 'replacelist', $subject);
function replacelist($groups) {
return "<ul>\n" .
preg_replace('/^#.*/m', ' <li>$0</li>', $groups[0])
. "</ul>\n";
}
a source to share
I'd say don't try to do it all in one regex - instead, first use a regex to match sets of sequential lines that start with characters #
and wrap those lines in a pair <ul></ul>
, then use a second regex (or not even a regex at all - you can just split on line breaks) to match each individual line and convert it to format <li></li>
.
a source to share
If it was me, I would:
- explode ("\ n", $ input) to an array, where 1 key = line
- execute through this array
- whenever you get a line that doesn't start with c # it is when adding closing / opening ul tags
Add a little more to deal with unexpected input (like two lines with no hash per line) and you're good to go.
a source to share
You can avoid regex altogether and just try the simpler approach by asking it to read a file, a string series (array of strings), and every time it encounters a non-hash-related string, it starts a new list, For example:
// You can get this by using file('filename') or
// just doing an explode("\n", $input)
$lines = array(
'I can haz a listz0rs!',
'# 42',
'# 126',
'I can haz another list plox?',
'# Hello, world!',
'# Welcome!'
);
$hashline = false;
$lists = array();
$curlist = array();
foreach ($lines as $line) {
if ($line[0] == '#')
$curlist[] = $line;
elseif ($hashline) {
$lists[] = $curlist;
$curlist = array();
$hashline = false;
}
}
A little cleaning might be ok, but hopefully it helps.
(after reading the new answers, this is mostly an explanation for a syntax error).
EDIT: you may want it to disable the # at the beginning of each line as well.
a source to share
It looks like the Syntax error has already explained what I am doing. But here goes a link to a working example .
a source to share
With such structured content, I wouldn't do it like a regex. How about a different approach?
$your_text = <<<END
I can haz a listz0rs!
# 42
# 126
I can haz another list plox?
# Hello, world!
# Welcome!
END;
function printUnorderedList($temp) {
if (count($temp)>0) {
print "<ul>\n\t<li>" .implode("</li>\n\t<li>", $temp) . "</li>\n</ul>\n";
}
}
$lines = explode("\n", $your_text);
$temp = array();
foreach($lines as $line) {
if (substr($line, 0, 1) == '#') {
$temp[] = trim(substr($line,1));
} else {
printUnorderedList($temp);
$temp = array();
echo $line . "\n";
}
}
printUnorderedList($temp);
a source to share