【问题标题】:C# Regex Match NOT inside self defined tagsC# 正则表达式匹配不在自定义标签内
【发布时间】:2018-06-10 14:50:19
【问题描述】:

我使用标签的形式是

[[MyTag]]Some Text[[/MyTag]]

为了在整个文本中找到这些标签,我使用以下表达式(这与这里的问题无关,但仅供参考):

\[\[(?<key>.*\w)]\](?<keyvalue>.*?)\[\[/\1\]\]

现在我喜欢只匹配和替换不在这些自定义标签内的文本 (MYSEARCHTEXT)。

例子:

[[Tag1]]Here I don't want to replace MYSEARCHTEXT[[/Tag1]]
But here MYSEARCHTEXT (1) should be replaced. And here MYSEARCHTEXT (2) needs to be replaced too.
[[AnotherTag]]Here I don't want to replace MYSEARCHTEXT[[/AnotherTag]]
And here I need to replace MYSEARCHTEXT (3) also.

MYSEARCHTEXT 是一个单词或短语,在这个例子中需要被找到 3 次。

【问题讨论】:

  • 究竟是什么?
  • 这些只是正则表达式组名。在示例中,“key”是第 1 组,包含“Tag1”,“keyvalue”是第 2 组,包含“这里我不想替换 MYSEARCHTEXT”。但是我需要所有不在这些标签内的 MYSEARCHTEXT 匹配项(在文本中可以有许多这样的标签,具有不同的键名)。
  • 看看this answer。您可以使用正则表达式类循环遍历每个匹配项,然后对前一组中的剩余文本(以及另一个匹配 MYSEARCHTEXT 的正则表达式)执行您需要的操作。

标签: c# regex


【解决方案1】:

也许这行得通?如果我正确理解了问题,这将在您的标签之外匹配 MYSEARCHTEXT 并且您的匹配项将在组中。这使用positive lookahead

https://regex101.com/r/C8Kuiz/2

(?:\[\[Tag1.*?\/Tag1\]\])\n?(?:.*)(?=(MYSEARCHTEXT))

【讨论】:

  • 差不多了,但您的匹配似乎太宽了,它只捕捉到 (2) 一个。并且我们需要考虑到整个文本可以有很多标签名不同的标签。
  • 原始示例中没有,我会调查一下。
【解决方案2】:

我有一个想法可以简化这一点。使用以下正则表达式匹配标记的文本:

\[.+?\][^\[\]]*?MYSEARCHTEXT[^\[\]]*?\[.+?\]\]

然后替换保留捕获组的字符串中的MYSEARCHTEXT

【讨论】:

  • 好吧,也许是我的错,我描述得不够清楚。我需要所有不在自定义标签内的“MYSEARCHTEXT”匹配项。您的解决方案捕获标签之外的整个文本。标签可以有不同的名称,这就是为什么我发布了我用于查找所有这些标签的情况的正则表达式示例。我更新了最初的帖子以使其更加清晰。
  • Aaaah 好的,抱歉,我没有正确理解。我编辑了我的答案! xD
  • 还没有,看我对jjmcc的回答。
【解决方案3】:

您可以使用以下解决方案,该解决方案使用您的模式版本并在 Regex.Replace 方法中添加替代方案,其中匹配评估器用作替换参数:

var pat = @"(?s)(\[\[(\w+)]].*?\[\[/\2]])|MYSEARCHTEXT";
var s = "[[Tag1]]Here I don't want to replace MYSEARCHTEXT[[/Tag1]]\nBut here MYSEARCHTEXT (1) should be replaced. And here MYSEARCHTEXT (2) needs to be replaced too.\n[[AnotherTag]]Here I don't want to replace MYSEARCHTEXT[[/AnotherTag]]\nAnd here I need to replace MYSEARCHTEXT (3) also.";
var res = Regex.Replace(s, pat, m =>
            m.Groups[1].Success ? m.Groups[1].Value : "NEW_VALUE");
Console.WriteLine(res);

C# demo

结果:

[[Tag1]]Here I don't want to replace MYSEARCHTEXT[[/Tag1]]
But here NEW_VALUE (1) should be replaced. And here NEW_VALUE (2) needs to be replaced too.
[[AnotherTag]]Here I don't want to replace MYSEARCHTEXT[[/AnotherTag]]
And here I need to replace NEW_VALUE (3) also.

模式详情

  • (?s) - RegexOptions.Singleline 内联修饰符选项(. 现在匹配任何字符)
  • (\[\[(\w+)]].*?\[\[/\2]]) - 第 1 组:
    • \[\[ - [[ 子字符串
    • (\w+) - 第 2 组:一个或多个单词字符
    • ]] - ]] 子字符串
    • .*? - 任何 0+ 个字符,尽可能少
    • \[\[/ - [[/ 子字符串
    • \2 - 与第 2 组捕获的文本相同
    • ]] - 文字 ]] 子字符串
  • | - 或
  • MYSEARCHTEXT - 一些要替换的模式。

当第 1 组匹配 (m.Groups[1].Success ?) 时,该值被放回,否则 NEW_VALUE 被插入到结果字符串中。

【讨论】:

    【解决方案4】:

    最好的方法是将两者分别匹配为匹配。
    然后根据哪个来决定替换哪个,写回哪个
    匹配。 (有人已经发布了这个解决方案,所以我不会复制它)

    另一种方法是完全放弃这一点并限定文本
    searchtext 之后的前瞻形式。

    这显示了如何做到这一点。

    var pat = @"(?s)MYSEARCHTEXT(?=(?:(?!\[\[/?\w+\]\]).)*?(?:\[\[\w+\]\]|$))";
    var res = Regex.Replace(s, pat, "NEW_VALUE");
    

    演示:https://ideone.com/KOtNik

    格式化:

     (?s)                          # Dot-all modifier
     MYSEARCHTEXT
     (?=                           # Qualify the text with an assertion
          (?:                           # Get non-tag characters
               (?! \[\[ /? \w+ \]\] )        
               . 
          )*?
          (?:                           # Up to -
               \[\[ \w+ \]\]                 # An open tag
            |  $                             # or, end of string
          )
     )
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-07-13
      • 1970-01-01
      相关资源
      最近更新 更多