我有一个程序,它获取 MD 文件中的每一行,然后将其作为每个
\n
行输出为新的 JSON 位。我遇到的问题是我无法获取正确的 JSON 来返回我的数组。被marked
解析后正常返回在控制台是这样的:
[["<h1>h1 header from md </h1>"]]
我希望我的返回看起来像这样而不使用对象:
{{"<h1>h1 header from md </h1>"}}
注意我通常会有不止一行MD,所以预期的回报应该是这样的:
{{"<h1>hello</h1>"}, {"<h1>world</h1>"}}
我该如何使用数组而不是对象来解决这个问题?
这里有一个更好、更通用的方法来处理这个问题。此外,它不会像您的那样删除字符串中间的“#”。这依赖于 ### 标头后面必须跟有空格的事实。
function render(md){
let code = "";
let mdLines = md.split('\n');
for(let i = 0; i < mdLines.length; i++){
if(mdLines[i][0] == "#") {
// We have a header. How many are there?
let s = mdLines[i].indexOf(" ")
if( mdLines[i].slice(0,s) == '#'.repeat(s) )
code += "<h"+s+">" + mdLines[i].slice(s+1) + "</h"+s+">";
else
code += mdLines[i];
}
else
code += mdLines[i];
};
return code;
}
let text1 = "## he#llo \n there \n # yooo"
let text2 = "# he#llo \n there \n ## yooo"
console.log(render(text1));
console.log(render(text2));
输出:
timr@Tims-NUC:~/src$ node x.js
<h2>he#llo </h2> there # yooo
<h1>he#llo </h1> there ## yooo
timr@Tims-NUC:~/src$
这显然是您想要测试的内容:
let text1 = "## he#llo\nthere\n# yooo"
let text2 = "# he#llo\nthere\n## yooo"
这是输出:
timr@Tims-NUC:~/src$ node x.js
<h2>he#llo</h2>there<h1>yooo</h1>
<h1>he#llo</h1>there<h2>yooo</h2>
timr@Tims-NUC:~/src$
如果你正在写的东西做“同样的事情,每一步只改变一件事”,那就是一个循环,或者如果你预见到一种确实需要
if
语句的情况,那么你通常希望这样解决它们您首先处理“最大的事情”(以确保不会失败)或使用 if-else
语句(也因此不会出现失败)。
您可能会考虑使用 switch,但 switch 语句是编程语言的遗留物,这些语言没有字典/键值对象来执行 O(1) 查找,而 JS、Python 等都这样做。因此,在 JS 中,您几乎总是更好地使用映射对象,并将 case 值作为属性键,将带有开关的 O(n) 代码路径转换为 O(1) 立即查找)
但是,在这种情况下,我们真正做的是简单的文本匹配,因此您可以使用工具集中最好的工具来实现:您可以使用正则表达式轻松获取
#
序列和“剩余文本”,并且然后使用捕获的数据生成替换 HTML :
function markdownToHTML(doc) {
return convertMultiLineMD(doc.split(`\n`)).join(`\n`);
}
function convertMultiLineMD(lines) {
// convert tables, lists, etc, while also making sure
// to perform inline markup conversion for any content
// that doesn't span multiple lines. For the purpose of
// this answer, we're going to ignore multi-line entirely:
return convertInlineMD(lines);
}
function convertInlineMD(lines) {
return lines.map((line) => {
// convert headings
line = line.replace(
// two capture groups, one for the markup, and one for the heading,
// with a third optional group so we don't capture EOL whitespace.
/^(#+)\s+(.+?)(\s+)?$/,
// and we extract the first group's length immediately
(_, { length: h }, text) => `<h${h}>${text}</h${h}>`
);
// then wrap bare text in <p>, convert bold, italic, etc. etc.
return line;
});
}
// And a simple test based on what you indicated:
const docs = [`## he#llo\nthere\n# yooo `, `# he#llo\nthere\n## yooo`];
docs.forEach((doc, i) => console.log(`[doc ${i + 1}]\n`, markdownToHTML(doc)));
但请注意,即使这仍然是编写转译器的一种简单方法,与基于 markdown 语法(“标记语言规范”语法,即规定哪些令牌可以跟随哪些其他令牌的规则),您可以通过跟踪我们正在处理的令牌类型来运行文档,并在我们传递令牌终止时即时转换。
(事实上,这就是正则表达式的工作原理:它们根据您指定的正则语法模式生成 DFA,然后通过该 DFA 运行输入,从而实现近乎完美的运行时性能)
function render(md) {
let code = ""; //For functions return
let mdLines = md.split("\n");
const re = /^\s*([#]{1,6})\s/;
for (let line of mdLines) {
const hash = line.match(re);
if (hash) {
const h = hash[1].length;
line = `<h${h}>${line.replace(re, "").trim()}</h${h}>`;
}
code += line;
}
return code;
}
let text1 = "## he#llo \n there \n # yooo";
let text2 = "# he#llo \n there \n ## yooo";
console.log(render(text1));
console.log(render(text2));