将引用语法转换为 HTML 的正则表达式

Regular expression for translating quoting syntax to HTML

我有一个针对我的用户的引用语法,类似于 SO:

So, Mike, you say:

>Lorem ipsum dolor sit amet, consectetur adipiscing elit.
>Nam mi dui, porta non gravida id
>sodales venenatis tellus

But this makes no sense!

也可以有多个引号。我需要使用 JavaScript:

将其翻译成这样的 HTML 标记
So, Mike, you say:

<div class="quote">
    Lorem ipsum dolor sit amet, consectetur adipiscing elit.
    Nam mi dui, porta non gravida id
    sodales venenatis tellus
</div>

But this makes no sense!

这是我想出的最好的,但它对每一行实施 HTML,而不是行块。

x = x.replace(/^&(amp;)?gt;([^\n]+)$/mg, "<div class=\"quote\">  </div>");

这样的正则表达式可以写吗?如果是,它会是什么样子?

这是试图用正则表达式操纵 HTML。 (我这么说是基于你正在搜索 > 的 HTML 实体而不是 > 的字面意思。)这几乎总是一个坏主意, 几乎 与尝试仅使用正则表达式解析 HTML 一样糟糕。 Obligatory Link.

您不能通过单个 replace 调用来完成此操作。但令我惊讶的是,您可以用两个或一个 outer 调用来完成,该调用使用函数回调来进行一堆内部调用。

这是两个调用版本:

x = x.replace(/^(?:(?:>|&gt;|&amp;gt;).*?[\r\n]+)+/gm, '<div class="quote">***$&</div>');
x = x.replace(/(?:\*\*\*|^)(?:>|&gt;|&amp;gt;)/gm, '');

第一个查找带有引号标记的重复行系列,并将 div 标记包裹在它们周围。 (我在集合中包含了一个原始 >,因此它会查找 >&gt;&amp;gt; [不过请参阅下面关于最后一个的注释]。)第二个删除引号。您不能在第一个 replace 中删除它们,因为您要替换整组行。另请注意,我必须为第一个标记添加前缀,因为一旦我们添加了 div 标记,它就不再位于一行的开头。

这是一个调用子调用的版本:

x = x.replace(/^(?:(?:>|&gt;|&amp;gt;).*?[\r\n]+)+/gm, function(m) {
  return '<div class="quote">' + m.replace(/^(?:>|&gt;|&amp;gt;)/gm, '') + '</div>';
});

它们有多强大?可能不是很多,请参阅上面答案的第一段。 :-)

旁注:您的正则表达式似乎正在寻找 &amp;gt; 作为引号标记。我在上面保留了它,但是如果你的 HTML 中有 &amp;gt;,你就有 double-encoded HTML,这通常是一个指标其他地方的问题。

两次调用版本的实时示例,其中包含各种不同引号标记的变体:

function test(x) {
  snippet.log("Before:");
  snippet.log(x);
  x = processString(x);
  snippet.log("After:");
  snippet.log(x);
  document.body.appendChild(document.createElement('hr'));
}

function processString(x) {
  x = x.replace(/^(?:(?:>|&gt;|&amp;gt;).*?[\r\n]+)+/gm, '<div class="quote">***$&</div>');
  x = x.replace(/(?:\*\*\*|^)(?:>|&gt;|&amp;gt;)/gm, '');
  return x;
}

test(
  "So, Mike, you say:\n" +
  "\n" +
  ">Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n" +
  "&amp;gt;Nam mi dui, porta non gravida id\n" +
  "&gt;sodales venenatis tellus\n" +
  "\n" +
  "But this makes no sense!\n"
);
test(
  "So, Mike, you say:\n" +
  "\n" +
  "&amp;gt;Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n" +
  ">Nam mi dui, porta non gravida id\n" +
  "&gt;sodales venenatis tellus\n" +
  "\n" +
  "But this makes no sense!\n"
);
test(
  "So, Mike, you say:\n" +
  "\n" +
  "&gt;Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n" +
  "&amp;gt;Nam mi dui, porta non gravida id\n" +
  ">sodales venenatis tellus\n" +
  "\n" +
  "But this makes no sense!\n"
);
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>

one-call-with-subcalls 版本的实例:

function test(x) {
  snippet.log("Before:");
  snippet.log(x);
  x = processString(x);
  snippet.log("After:");
  snippet.log(x);
  document.body.appendChild(document.createElement('hr'));
}

function processString(x) {
  x = x.replace(/^(?:(?:>|&gt;|&amp;gt;).*?[\r\n]+)+/gm, function(m) {
    return '<div class="quote">' + m.replace(/^(?:>|&gt;|&amp;gt;)/gm, '') + '</div>';
  });
  return x;
}

test(
  "So, Mike, you say:\n" +
  "\n" +
  ">Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n" +
  "&amp;gt;Nam mi dui, porta non gravida id\n" +
  "&gt;sodales venenatis tellus\n" +
  "\n" +
  "But this makes no sense!\n"
);
test(
  "So, Mike, you say:\n" +
  "\n" +
  "&amp;gt;Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n" +
  ">Nam mi dui, porta non gravida id\n" +
  "&gt;sodales venenatis tellus\n" +
  "\n" +
  "But this makes no sense!\n"
);
test(
  "So, Mike, you say:\n" +
  "\n" +
  "&gt;Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n" +
  "&amp;gt;Nam mi dui, porta non gravida id\n" +
  ">sodales venenatis tellus\n" +
  "\n" +
  "But this makes no sense!\n"
);
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>

这是如何完成的:匹配所有块,然后在回调函数内,拆分它并删除初始 > 并包装在 div:

var s = 'So, Mike, you say:\n\n>Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n>Nam mi dui, porta non gravida id\n>sodales venenatis tellus\n\nBut this makes no sense!';
var res = s.replace(/^(?:(?:>|&(?:amp;)?gt;)[^\n]+)+/gm, function(m, grp1, grp2, offset, input) {
     return m.split("\n").map(function(el) {
         return '<div class="quote">' + el.replace(/(?:>|&(?:amp;)?gt;)/g,'') + "</div>";
     }).join("\n");
});
alert(res);