【问题标题】:Using text styling to create a list with sublists使用文本样式创建带有子列表的列表
【发布时间】:2013-10-23 15:14:15
【问题描述】:

我正在尝试制作标记以格式化有序列表,这是标记样式:

$strings = "1. dog
1. cat
1. fish
 1. horse
 1. monkey
1. pig
";

该列表中的horsemonkey 应该是子列表的一部分,因为它们在数字前有一个空格。这是我正在使用的代码:

function blq($match){
    $str = preg_replace("/^1\. (.+?)$/m", "<li>$1</li>", $match[0]);
    $str = preg_replace_callback("/(?:^1\. .+(\n|$))+/m", 'blq', $str);
    return "<ol>$str</ol>";
}

$string = preg_replace_callback("/(?:^ ?1\. .+(\n|$))+/m", 'blq', $strings);

echo $string;

该代码正在创建此输出:

<ol><li>dog
</li>
<li>cat
</li>
<li>fish
</li>
 1. horse
 1. monkey
<li>pig
</li>
</ol>

horsemonkey 没有创建为子列表,只是被忽略了。我觉得我离答案越来越近了,但我不知道该怎么做才能得到那个答案......

注意我想允许无限数量的子列表

【问题讨论】:

  • 只是对一些事情感到好奇。双引号中的$1 不会尝试插入吗? (它们不应该用单引号吗?)另外,您确定要使用/m 修饰符吗?如果是这样,(\n|$) 对我来说没有意义,因为 $ 匹配 \n
  • $1 不是有效变量,因此它被读取为文本。我正在使用/m,因为我正在进行多行搜索,所以我认为这是正确的。对于(\n|$),我不确定。

标签: php regex markdown preg-replace-callback


【解决方案1】:
<?php

$text = "1. dog
1. cat
1. fish
 1. horse
  1. duck
   1. goose
  1. swan
 1. monkey
  1. chimpanzee
  1. orangutan
  1. whale
1. pig
";

function callback($match) {
    $out = preg_replace_callback("/(^($match[2] +)1\. .+(\\n|$))(?1)*/m", 'callback', $match[0]);
    $out = preg_replace("/^$match[2]1\. (.+)$/m", "<li>$1</li>", $out);
    return "<ol>\n$out</ol>\n";
}

$html = preg_replace_callback("/(^( *)1\. .+(\\n|$))(?1)*/m", 'callback', $text);

echo $html;

?>

这里是an ideone demo


这是一个非常巧妙的想法,递归地使用preg_replace_callback。另外,你是对的,$-strings 不会在双引号内插值,除非它们是一个集合变量;我总是忘记这一点。而且,您使用/m 是正确的,因为您希望^ 匹配每行的开头(而不是整个字符串的开头),并且您使用(\n|$) 也是正确的,尽管$ 匹配结尾/m 模式下的每一行——否则,量词 + 将不起作用,因为 $ 实际上不会使用 \n。当我第一次阅读您的问题时,我没有看到这些事实。

现在,让我们从第一个表达式开始:

/(^( *)1\. .+(\\n|$))(?1)*/m

实际上,递归子表达式(?1) 不是必需的,除非是速记。让我们扩展一下:

/(^( *)1\. .+(\\n|$))(^( *)1\. .+(\\n|$))*/m
 |                  ||                  |
 +------------------++------------------+

所以我们有两个相同的部分。为什么不像你那样使用+?因为我只想捕获缩进 first 行的空格数。这些空间存储在$match[2]

在回调中,我们将这些空格带回来,再加上一个或多个空格:

/(^($match[2] +)1\. .+(\\n|$))(?1)*/m

这样,我们只会在preg_replace_callback 递归的每个级别上查看当前缩进级别下方 的级别(更多 个空格)。随着递归的展开,只有缩进的行恰好是该级别的空格数 $match[2],被包裹在 &lt;li&gt;&lt;/li&gt; 中,

/^$match[2]1\. (.+)$/m

在返回整个包裹在&lt;ol&gt;&lt;/ol&gt;之前。

【讨论】:

  • 非常好的答案,甚至更好的解释+1
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多