在多行重复模式上应用PHP正则表达式替换

时间:2010-05-01 04:45:06

标签: php regex

假设我有这样的意见:

I can haz a listz0rs!
# 42
# 126
I can haz another list plox?
# Hello, world!
# Welcome!

我想拆分它,以便每组哈希启动行成为一个列表:

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>

如果我针对正则表达式运行输入“/(?:(?:(?&lt; = ^#)(。*)$)+)/ m”,我得到以下结果:

Array
(
    [0] => Array
    (
        [0] => 42
    )
    [1] => Array
    (
        [0] => 126
    )
    [2] => Array
    (
        [0] => Hello, world!
    )
    [3] => Array
    (
        [0] => Welcome!
    )
)

这很好,花花公子,但它不区分两个不同的列表。我需要一种方法来使量化器返回所有出现的串联字符串,或者理想情况下,返回所有出现的数组。

理想情况下,这应该是我的输出:

Array
(
    [0] => Array
    (
        [0] => 42
        [1] => 126
    )
    [1] => Array
    (
        [0] => Hello, world!
        [1] => Welcome!
    )
)

有没有办法实现这一目标,如果没有,是否还有其他选择?

6 个答案:

答案 0 :(得分:1)

如果你想用正则表达式做这件事,你需要两个。使用正则表达式^(#.*\r?\n)+匹配每个列表并在其周围添加标记。在每个列表中(与第一个正则表达式匹配),使用^#.*搜索并替换<li>$0</li>以在每个列表项周围添加标记。两个正则表达式都需要^来匹配换行符(PHP中的/m标志)。

在PHP中,您可以使用preg_replace_callbackpreg_replace在几行代码中实现此目的。

$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 :(得分:0)

我想说不要试图在一个正则表达式中完成所有操作 - 相反,首先使用正则表达式来匹配所有以#符号开头的连续行的集合,并用{{包裹这些行一对。然后使用第二个正则表达式(或者甚至根本不是正则表达式 - 你可以在换行符上拆分)来匹配每一行,并将其转换为<ul></ul>格式。

答案 2 :(得分:0)

如果是我,我会:

  1. 将(“\ n”,$ input)分解为数组,其中1 key = line
  2. 通过该阵列预告
  3. 每当你得到一个不以#开头的行时,就是当你添加你的结束/开放ul标签时
  4. 添加一点来处理意外的输入(比如一行中的两个非散列行)并且你很好。

答案 3 :(得分:0)

你可以完全避免正则表达式,只需尝试一种更简单的方法,让它逐行读取文件(一个行数组),每次遇到一个非哈希启动的行时,它就会启动一个新的列表。像这样:

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

可能需要进行一些清理,但希望它有所帮助。

(在阅读新答案后,这基本上是对Syntax Error答案的深入解释。)

编辑:您可能希望它在每行的开头删除#。

答案 4 :(得分:0)

看起来Syntax Error已经解释了我在做什么。但是这里链接到working example

答案 5 :(得分:0)

对于像这样的结构化内容,我不会将其作为正则表达式。另一种方法怎么样?

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