【问题标题】:Java regex match markdown syntax for headingsJava 正则表达式匹配标题的降价语法
【发布时间】:2017-09-24 13:37:41
【问题描述】:

我有一个带有 markdown 语法的字符串,我希望能够找到标题的 markdown 语法,即 h1 = #、h2 = ## 等。

我知道每当我找到一个标题时,它就位于行首。我也知道每行只能有一个标题。例如,“###This is a heading”将匹配我的 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 标记包围整个匹配项,例如:“###Heading”,但由于某种原因它不起作用

//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 这里。您可以使用"(?&lt;!#)#{6}\\b",然后使用简单的tmp = tmp.replaceAll("(?&lt;!#)#{6}\\b", "&lt;b&gt;$0&lt;/b&gt;")
  • @WiktorStribiżew 我试过你的解决方案,但问题是匹配只返回 #:s,而不是后面的文本
  • 如果您需要匹配 # 序列开头的行,请参阅我的更新答案。总是向问题本身添加新的细节,而不仅仅是 cmets。
  • @WiktorStribiżew 抱歉,对这个有点陌生。现在看看你的答案。另外,问题已更新:)
  • 好,我投了赞成票,因为这是一个展示努力的好问题。而现在,真的清晰多了。

标签: java html regex markdown stringbuffer


【解决方案1】:

没有必要转义#,因为它不是一个特殊的正则表达式元字符。此外,^字符串起始锚,因此模式中的所有后视都是多余的,因为它们总是返回 true(因为在开始之前没有字符一个字符串)。

您似乎想在单词 char 之前匹配指定数量的 #。使用

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 demo

结果:

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

详情

  • (?m) - 现在,^ 匹配行首
  • ^ - 行首
  • #{6}(?!#) - 正好 6 个 # 符号
  • (.*) - 第 1 组: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}(?!#)(.*)");

【讨论】:

  • 我尝试了你的解决方案,它就像一个魅力!非常感谢大佬,非常感谢。 :-)
【解决方案2】:

你可以试试this:

^(#{1,6}\s*[\S]+)

正如你所提到的,标题只出现在一行的开头,因此你不需要向后看。

更新: 如果你想加粗以标题开头的整行,那么你可以试试这个:

^(#{1,6}.*)

并替换为:

<b>$1</b>

Regex Demo

示例 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);

Run java source

【讨论】:

  • 谢谢!唯一的问题是 heaidng 可能不止一个词,我想我想检查 #:s 然后获取后面的所有文本,直到最后。你对如何调整你的解决方案有什么建议吗?我想也许是 \\b,但那只给了我 #:s
  • 所以你想要整行?
  • 是的,如果写了#,那么后面的所有内容都将作为标题包含在内,直到用户按下回车键。
  • 您的解决方案效果很好。我的问题是我必须对每个标题(h1,h2 ...)进行单独检查,因为我在程序的其他部分使用了该模式,所以这样更容易。现在,如果我有“## Some text here”,它对 h1 和 h2 都匹配 true,但只有 h2 应该是 true。我正在构建您的解决方案,但还没有按照我的意愿工作。
  • @Kaffemakarn:如果你想将整行加粗是真的吗?请在问题中添加详细信息。
猜你喜欢
  • 2012-04-15
  • 2019-01-12
  • 1970-01-01
  • 1970-01-01
  • 2010-10-30
  • 1970-01-01
  • 1970-01-01
  • 2011-03-30
  • 2011-05-26
相关资源
最近更新 更多