所以我正在尝试为 JavaScript 编写一个正则表达式,它允许我用标记替换 ** 作为一种自滚动的 Markdown 到 HTML 转换器。
例如
**bold**
-> <strong>bold</strong>
但是
\**not**
-> **not**
因为*
被逃脱了。
我有以下似乎运行良好的正则表达式:
/(?<!\\)(?:\\\\)*(\*\*)([^\\\*]+)(\*\*)/g
但是JS不支持lookbehinds!我使用前瞻重写了它:
/(\*\*)([^\\\*]+)*(\*\*)(?!\\)(?:\\\\)*/g
但这需要我反转字符串,这是不受欢迎的,因为我需要支持多字节字符 ( see here )。我并不完全反对使用该答案中提到的库,但我更喜欢一种不需要我在可能的情况下添加的解决方案。
有没有一种方法可以在不使用 look behinds 的情况下重写我的正则表达式?
编辑:
在进一步思考这个问题之后,我什至开始质疑正则表达式是否是解决这个问题的最佳方法,但出于兴趣我会把这个问题搁置。
最佳答案
解决缺少后视的一种方法是首先匹配不需要的模式,然后使用交替匹配所需的模式。然后应用条件替换,将不想要的模式替换为它们自己,将想要的模式替换为您真正想要的。
在您的特定情况下,这意味着匹配 \*
首先和**<something>**
只有在那之后。然后使用
input.replace(/\\\*|\*\*(.*?)\*\*/, function(m, p1) {
return m == '\\*' ? m : '<strong>' + p1 + '</strong>';
})
做条件替换。
但真正的正则表达式要复杂得多。首先,您需要避免转义反斜杠本身(即 \\**bold**
应变为 \\<strong>bold</strong>
)。所以你需要匹配 \\
分别使用与 \*
相同的方式.
二、**
之间的表达式和 **
也可能包含一些转义星号和斜杠。为了解决这个问题,您需要匹配 \\
和 \**
明确地并且(使用交替)仅在此之后任何其他非贪婪的。这可以表示为 (?:\\\\|\\\*\*|\*(?!\*)|[\S\s])*?
.
因此最终的正则表达式变为
\\\\|\\\*|\*\*((?:\\\\|\\\*\*|\*(?!\*)|[\S\s])*?)\*\*
演示:https://regex101.com/r/Da35r5/1
JavaScript 替换演示:
function convert() {
var md = document.getElementById("md").value;
var re = /\\\\|\\\*|\*\*((?:\\\\|\\\*\*|\*(?!\*)|[\S\s])*?)\*\*/g;
var html = md.replace(re, function(match, p1) {
return match.startsWith('\\') ? match : '<strong>' + p1 + '</strong>';
});
document.getElementById("html").value = html;
}
<span style="display:inline-block">
MD
<textarea id="md" cols="20" rows="10" style="display:block">
**bold**
**foo * bar **
**foo \** bar**
**fo\\\\** bar** **
\**bold** **
\\**bold**
** multi
line**
</textarea>
</span>
<span style="display:inline-block">
HTML
<textarea id="html" cols="50" rows="10" style="display:block">
</textarea>
</span>
<button onclick="convert()" style="display:block">Convert</button>
关于javascript - Markdown 加粗不带回溯的正则表达式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44183199/