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?

+2


a source to share


6 answers


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";
}

      

+1


a source


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>

.



0


a source


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.

0


a source


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.

0


a source


It looks like the Syntax error has already explained what I am doing. But here goes a link to a working example .

0


a source


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);

      

0


a source







All Articles