【问题标题】:Regex to find markup正则表达式查找标记
【发布时间】:2019-02-01 21:54:43
【问题描述】:

我确定有人已经问过这个问题,但我不知道在 google 中搜索什么词才能找到这些答案。

我必须将带有标记的文本“翻译”为 html(或 rtf 或 xaml)。 “粗体”的标记是 *。如果我希望粗体文本包含文字 *,我必须用反斜杠掩盖它。

所以,标记的文本...

This is *ju\*st* a test.

...应该翻译为“这是ju*st测试。”

我正在寻找一种正则表达式模式,以便在我的标记文本中将所有匹配“翻译”为粗体。

现在我被这个困住了(一个字面星号后跟一个或多个不是星号的字符(尽可能少),然后是一个字面星号)

\*[^*]+?\*

但是如何增强“一个或多个不是星号的字符”部分,使其不会停留在以反斜杠开头的星号处?

我想在 .NET 项目中使用这个正则表达式,以防语言之间存在差异。

【问题讨论】:

  • \*(\\\*|[^*])+?\* -- 是反斜杠星号还是不是星号的字符?
  • 你需要(?<=(?<!\\)(?:\\{2})*)\*[^\\*]*(?:\\.[^\\*]*)*\*。请参阅.NET regex demo 不要使用 regex101 来测试 .NET 正则表达式模式,它不支持 .NET 正则表达式语法。
  • 你不能只使用\*(\\\*|[^*])+?\*,因为这个模式does not make sure第一个匹配的*不是一个转义的星号。
  • @Wiktor:你能为新手解释一下你的长正则表达式模式吗?

标签: regex


【解决方案1】:

你可以使用

(?<=(?<!\\)(?:\\{2})*)\*[^\\*]*(?:\\.[^\\*]*)*\*

请参阅.NET regex demo

详情

  • (?&lt;=(?&lt;!\\)(?:\\{2})*) - 一个积极的向后看,确保在当前位置之前没有 \ 转义字符。换句话说,它匹配紧接在前面的位置:
    • (?&lt;!\\) - 没有 \ char 后跟
    • (?:\\{2})* - 双反斜杠的任何零次或多次重复
  • \* - 一个 * 字符
  • [^\\*]* - 除了\* 之外的零个或多个字符
  • (?: - 非捕获组匹配的开始...
    • \\. - 使用\ char 转义的任何字符(换行符除外,使用RegexOptions.Singleline 编译模式以允许任何转义字符)
    • [^\\*]* - 除了\* 之外的零个或多个字符
  • )* - 零次或多次
  • \* - 一个 * 字符。

【讨论】:

  • 谢谢。这个相当复杂的正则表达式适用于我测试过的所有情况,但我真的不知道为什么。我认为第四个主要要点中的 [^\\*]* 正在捕获两个标记 * 字符之间的所有文本。但是对于这个正则表达式部分,捕获是否应该在任何反斜杠或星号之前停止,无论它们是否相互成功,无论它们是否以正确的顺序出现?
  • @Nostromo 您需要查看整个\*[^\\*]*(?:\\.[^\\*]*)*\* 部分。它匹配从* 直到第一次遇到* 匹配其间的任何转义字符。 \* 匹配*[^\\*]* 匹配除\* 之外的任何字符,但随后(?:\\.[^\\*]*)* 匹配任何转义字符的0 次或多次重复 + 除@ 以外的任何字符987654354@ 和 \,因此,可以匹配未转义的 * 之后的所有转义字符。然后,\* 匹配 *。这是一个unrolled\*([^\\*]|\\.)*\* 模式,可能更易于分析,但效率较低。
  • 现在我不太在意效率,我宁愿理解一个Regex,即使一年后看代码。所以,现在我坚持你建议的“滚动”正则表达式。谢谢。
  • @Nostromo 如果你在Java中使用\*([^\\*]|\\.)*\*,你肯定会得到堆栈溢出异常。使用展开的版本。即使是非捕获组 - \*(?:[^\\*]|\\.)*\* - 也无济于事。
【解决方案2】:

您想从一个标记星匹配到另一个标记星。 在您的标记语言中,文字星实际上不仅是*,而且是\*。 在正则表达式中,这翻译为\\\*:一个反斜杠,必须转义,然后是一个星号,也必须转义。

因此,您需要在您的模式中指定您正在寻找一个标记星,而不是一个文字星

\*.*[^\\]\*

\*             a markup star
  .*           followed by any character
    [^\\]\*    then a markup star, that is, one not escaped by a backslash

这有点不对劲,因为.* 是贪心的,所以在"*ju\*st* *ju\*st* 中,它将匹配整个字符串,从第一个星到最后一个星。

您可以在大多数引擎中使用星号修饰符的惰性/非贪婪版本:*?。 于是就变成了:

\*.*?[^\\]\*

\*             a markup star
  .*?          followed by any character, but as few as possible
     [^\\]\*   then a markup star, that is, one not escaped by a backslash

用 Python 小试一试:

>>> s = r"*ju\*st* *ju\*st*"
>>> re.match(r"\*.*[^\\]\*", s)
<re.Match object; span=(0, 17), match='*ju\\*st* *ju\\*st*'>
>>> re.match(r"\*.*?[^\\]\*", s)
<re.Match object; span=(0, 8), match='*ju\\*st*'>

如果您的正则表达式引擎不支持惰性修饰符,您需要明确此行为:

\*([^*]|\\\*)*[^\\]\*

\*                       a markup star
  (                      then either...
   [^*]                  ...any character but a star...
       |                 ...or...
        \\\*             ...a star prefix by a backslash, ie a literal star
            )*           any number
              [^\\]\*    then a markup star

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-12
    • 2010-12-10
    • 1970-01-01
    • 1970-01-01
    • 2018-05-24
    相关资源
    最近更新 更多