You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Marked.js自定义列表扩展误识别行内内容为列表的问题求助

Marked.js自定义列表扩展误识别行内内容为列表的问题求助

大家好,我最近在给Marked.js做一个自定义列表扩展,想让它支持字母、罗马数字这些不同样式的有序列表,就像HTML里的<ol type>那样。目前大部分情况都正常,但遇到一个奇怪的问题,想请教一下大家。

我用Marked.js解析Markdown,原生Markdown不支持字母、罗马数字这类有序列表样式,所以我写了下面这个自定义扩展代码:

const customList = {
  name: "customList",
  level: "block",
  start(src) {
    return src.match(/(?:^|\n)(\s*)(-|\+|\*|\d+\.|[A-Za-z]+\.|[iIvVxX]+\.)(\s+)/)?.index;
  },
  tokenizer(src, tokens) {
    const rule = /^([^\S\r\n]*)(-|\+|\*|\d+\.|[A-Za-z]+\.|[iIvVxX]+\.)(\s+)(.*)/;
    const textRule = /^([^\S\r\n]*)(.*)/;
    const match = rule.exec(src);
    let style;
    if (match) {
      if (/-/.test(match[2])) style = "-";
      else if (/\+/.test(match[2])) style = "+";
      else if (/\*/.test(match[2])) style = "*";
      else if (/\d+\./.test(match[2])) style = "1";
      else if (/[IVX]+\./.test(match[2])) style = "I";
      else if (/[ivx]+\./.test(match[2])) style = "i";
      else if (/[A-Z]+\./.test(match[2])) style = "A";
      else if (/[a-z]+\./.test(match[2])) style = "a";

      const items = [];
      let remainingSrc = src;
      let prevIndent = match[1].length;
      let itemText = "", raw = "";

      while (remainingSrc) {
        const itemMatch = rule.exec(remainingSrc);
        const textMatch = textRule.exec(remainingSrc);

        if (itemMatch && itemMatch[1].length === prevIndent) {
          let itemStyle;
          if (/-/.test(itemMatch[2])) itemStyle = "-";
          else if (/\+/.test(itemMatch[2])) itemStyle = "+";
          else if (/\*/.test(itemMatch[2])) itemStyle = "*";
          else if (/\d+\./.test(itemMatch[2])) itemStyle = "1";
          else if (/[IVX]+\./.test(itemMatch[2])) itemStyle = "I";
          else if (/[ivx]+\./.test(itemMatch[2])) itemStyle = "i";
          else if (/[A-Z]+\./.test(itemMatch[2])) itemStyle = "A";
          else if (/[a-z]+\./.test(itemMatch[2])) itemStyle = "a";
          else break;

          if (itemStyle !== style) break;

          if (itemText) {
            const itemTokens = [];
            this.lexer.inlineTokens(itemText, itemTokens);
            items.push({ type: "customListItem", raw: raw, tokens: itemTokens });
          }
          itemText = itemMatch[4].trim();
          raw = itemMatch[0];
          remainingSrc = remainingSrc.slice(itemMatch[0].length + 1);
        } else if (textMatch && textMatch[1].length === prevIndent) {
          itemText += "\n" + textMatch[2];
          raw += "\n" + textMatch[0];
          remainingSrc = remainingSrc.slice(textMatch[0].length + 1);
        } else break;
      }

      if (itemText) {
        const itemTokens = [];
        this.lexer.inlineTokens(itemText, itemTokens);
        items.push({ type: "customListItem", raw: raw, tokens: itemTokens });
      }

      const token = {
        type: "customList",
        raw: src.slice(0, src.length - remainingSrc.length),
        style: style,
        items: items
      };
      return token;
    }
  },
  renderer(token) {
    const listItems = token.items.map(item => `<li>${this.parser.parseInline(item.tokens)}</li>` ).join('\n');
    if (token.style === "-" || token.style === "+" || token.style === "*") 
      return `<ul>\n${listItems}\n</ul>\n`;
    else if (token.style === "1" || token.style === "I" || token.style === "i" || token.style === "A" || token.style === "a") 
      return `<ol type="${token.style}">\n${listItems}\n</ol>\n`;
  },
  childTokens: ["items"]
};

marked.use({ extensions: [customList] });

目前大部分场景下它都能正常工作,比如:

  • 例子1:执行marked.parse("1. first\n2. second\n3. third"),输出正确的有序列表:
  1. first
  2. second
  3. third
  • 例子2:执行marked.parse("A. first\nB. second\n* first\n* second"),能正确区分字母有序列表和无序列表:
  1. first
  2. second
  • first
  • second

但是当我执行marked.parse("1 + 1")的时候,输出却变成了:

1

  • 1

这明显不符合预期,我本来希望只有出现在行首(周围是空白字符)的列表标记才会被识别成列表,而不是行中间的+符号。

我试着在tokenizer函数里加了console.log(src)来排查,发现处理1 + 1的时候,居然输出了两次内容:1 + 1和+ 1,这让我完全摸不着头脑,不知道为什么会出现这种情况。

我是JavaScript新手,代码可能写得有点粗糙,有没有大佬能帮我看看问题出在哪?如果需要更多信息的话,我随时补充,谢谢大家!

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.08 11:15:31