Java正则表达式匹配Markdown语法中的标题格式

6
我有一个包含Markdown语法的字符串,我想找到标题的Markdown语法,例如h1=#,h2=##等等。
我知道每当我找到一个标题时,它都在行的开头。我还知道每行只能有一个标题。例如,“###这是一个标题”将匹配我的h3模式,但不会匹配我的h2或h1模式。这是我目前的代码:
h1 = Pattern.compile("(?<!\\#)^\\#(\\b)*");
h2 = Pattern.compile("(?<!\\#)^\\#{2}(\\b)*");
h3 = Pattern.compile("(?<!\\#)^\\#{3}(\\b)*");
h4 = Pattern.compile("(?<!\\#)^\\#{4}(\\b)*");
h5 = Pattern.compile("(?<!\\#)^\\#{5}(\\b)*");
h6 = Pattern.compile("(?<!\\#)^\\#{6}(\\b)*");

每当我使用\\#时,我的编译器(IntelliJ)会告诉我:“冗余字符转义”。只要我使用\\#它就会这样做。据我所知,在正则表达式中,#不应该是一个特殊字符,因此用两个反斜杠来转义它应该允许我使用它。
当我找到匹配项时,我想用粗体HTML标签把整个匹配项括起来,就像这样:"###标题",但出于某种原因它不起作用。
//check for heading 6
Matcher match = h6.matcher(tmp);
StringBuffer sb = new StringBuffer();
while (match.find()) {
    match.appendReplacement(sb, "<b>" + match.group(0) + "</b>");
}
match.appendTail(sb);
tmp = sb.toString();

编辑

所以我必须单独查看每个标题,不能以相同的方式查看标题1-6(这与我程序的其他部分使用相同的模式有关)。 我现在知道的是:

  • 如果字符串中有标题,则它位于开头。
  • 如果以标题开头,则其后跟的整个字符串都被视为标题,直到用户按Enter键。
  • 如果我有“## 这是一个标题”,则对于h2必须匹配true,但对于h1必须匹配false。
  • 当我找到匹配项时,此“## 这是一个标题”变为“## 这是一个标题”。

你无需转义 #。在这里甚至不需要使用 Matcher#appendReplacement。你可以使用 "(?<!#)#{6}\\b",然后使用简单的 tmp = tmp.replaceAll("(?<!#)#{6}\\b", "<b>$0</b>") - Wiktor Stribiżew
@WiktorStribiżew 我尝试了你的解决方案,但问题是匹配只返回#:s,而不是其后跟随的文本。 - Kaffemakarn
如果您需要匹配以#序列开头的行,请参考我的更新答案。始终将新细节添加到问题本身,而不仅仅是评论中。 - Wiktor Stribiżew
1
@WiktorStribiżew 对不起,我有点新手。现在正在查看您的答案。另外,问题已经更新 :) - Kaffemakarn
很好,我点赞了它,因为这是一个很好的问题,展示了努力。现在,它真的更清晰了。 - Wiktor Stribiżew
2个回答

6

没有必要转义#,因为它不是特殊的正则表达式元字符。另外,^是字符串的开始,所以你模式中的所有回顾都是多余的,因为它们总是返回true(因为在字符串开头之前没有字符)。

您似乎想匹配一个单词字符前指定数量的#。使用

String s = "###### Heading6 Something here\r\n" +
           "###### More text \r\n" +
          "###Heading 3 text";
Matcher m = Pattern.compile("(?m)^#{6}(?!#)(.*)").matcher(s);
String result = m.replaceAll("<b>$1</b>");
System.out.println(result);

请查看Java演示

结果:

<b> Heading6 Something here</b>
<b> More text </b>
###Heading 3 text

细节:

  • (?m) - 现在,^ 匹配行的开头
  • ^ - 行的开头
  • #{6}(?!#) - 恰好 6 个 # 符号
  • (.*) - 第一组: 到行末之前的除换行符外的0个或多个字符。

因此,你的正则表达式定义将如下所示:

h1 = Pattern.compile("(?m)^#(?!#)(.*)");
h2 = Pattern.compile("(?m)^#{2}(?!#)(.*)");
h3 = Pattern.compile("(?m)^#{3}(?!#)(.*)");
h4 = Pattern.compile("(?m)^#{4}(?!#)(.*)");
h5 = Pattern.compile("(?m)^#{5}(?!#)(.*)");
h6 = Pattern.compile("(?m)^#{6}(?!#)(.*)");

1
我尝试了你的解决方案,它非常好用!非常感谢你,真的很感激。 :-) - Kaffemakarn

5
你可以尝试使用 这个 工具:
^(#{1,6}\s*[\S]+)

正如您所提到的,标题只出现在一行的开头,因此您不需要查看之前的内容。

更新: 如果您想要将以标题开头的整行加粗,您可以尝试以下方法:

^(#{1,6}.*)

并替换为:

<b>$1</b>

正则表达式演示

Java示例源代码:

final String regex = "^(#{1,6}\\s*[\\S]+)";
final String string = "#heading 1 \n"
     + "bla bla bla\n"
     + "### heading 3 djdjdj\n"
     + "bla bla bla\n"
     + "## heading 2 bal;kasddfas\n"
     + "fbla bla bla";
final String subst = "<b>$1</b>";
final Pattern pattern = Pattern.compile(regex, Pattern.MULTILINE);
final Matcher matcher = pattern.matcher(string);
final String result = matcher.replaceAll(subst);
System.out.println(result);

运行Java源代码


谢谢!唯一的问题是标题可能不止一个单词,我想我需要检查#:s,然后获取其后的所有文本,直到结尾。您有什么建议可以调整您的解决方案吗?我想也许是\b,但那只给了我#:s。 - Kaffemakarn
你想要完整的那一行吗? - Mustofa Rizwan
是的,如果写了一个#,那么接下来的所有内容都将被包含在标题中,直到用户按下回车键。 - Kaffemakarn
你的解决方案非常好。我的问题是我必须为每个标题(h1,h2...)进行单独的检查,因为我在程序的其他部分中使用该模式,所以这样做更容易。现在,如果我有“## 这里有一些文本”,它会对h1和h2都匹配为true,但只有h2应该是true。我正在基于你的解决方案构建,但还没有达到我想要的效果。 - Kaffemakarn
@Kaffemakarn:如果你想将整行加粗 是否正确?请在问题中添加细节。 - Wiktor Stribiżew

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接