【问题标题】:C# Regex for a match outside a specific regionC# 正则表达式用于特定区域之外的匹配
【发布时间】:2011-04-08 15:46:38
【问题描述】:

我必须在另一个字符串 (haystack) 中找到某个字符串 (needle) 的出现,而这些字符串不会出现在特定的“大括号”之间。

例如考虑这个干草堆: “开始一些事情 结束一些其他事情 开始一些其他事情 END 还有一些事情。” 还有这个针: “一些” 用大括号“BEGIN”和“END”

我想找出所有不在牙套之间的针。 (有两个匹配:“some”后跟“other”和“some”后跟“more”)

我想我可以使用带有负前瞻/后视的正则表达式来解决这个问题,但是如何解决呢?

我试过了

(?<!(BEGIN))some(?!(END))

这给了我 4 个匹配项(显然因为“开始”和“结束”之间没有直接包含“一些”)

我也试过了

(?<!(BEGIN.*))some(?!(.*END))

但这根本没有给我任何匹配项(显然因为每根针都以某种方式前面有一个“BEGIN”)

不,我被卡住了。

这是我使用的最新 C# 代码:

string input = "BEGIN something END some other thing BEGIN something else END yet some more things.";
global::System.Text.RegularExpressions.Regex re = new Regex(@"(?<!(BEGIN.*))some(?!(.*END))");
global::System.Text.RegularExpressions.MatchCollection matches = re.Matches(input);
global::NUnit.Framework.Assert.AreEqual(2, matches.Count);

【问题讨论】:

  • 除了使用正则表达式之外,您是如何尝试其他解决方案的?

标签: c# regex


【解决方案1】:

这样的东西对你有用吗:

(?:^|END)((?!BEGIN).*?)(some)(.*?)(?:BEGIN|$)

这似乎与您的文本匹配,因为我使用 RegExDesigner.NET 进行了测试。

【讨论】:

  • 上面的表达式做到了!非常感谢。我只需要得到 Group[2].Value 而不是 Group[0].Value,但这很好。也感谢您提到 RegExDesigner。我以前没听说过。
  • 我认为如果您在同一个endbegin 之间有多个somes - "some some END BEGIN some some",则此表达式不起作用
【解决方案2】:

一个简单的选择是跳过你不想匹配的部分,只捕获你需要的针:

MatchCollection matches = Regex.Matches(input, "BEGIN.*?END|(?<Needle>some)");

通过从所有匹配中取出成功的“Needle”组,您将获得两个“一些”:

IEnumerable<Group> needles = matches.Cast<Match>()
                                    .Select(m => m.Groups["Needle"])
                                    .Where(g => g.Success);

【讨论】:

  • +1,这很聪明。你测试过吗?我可以告诉你的想法是,交替运算符 (|) 会使任何匹配 BEGIN.*?END 的东西都短路到捕获组之外,但我不认为交替在正则表达式中是短路的。
  • 更新:它确实有效。 rubular.com/r/6mKSumbyuF。我一定会记住这个技巧的。
  • @Justin - 谢谢!这实际上与短路无关,它与匹配引擎的工作方式有关 - 如果它找到与 start-end 块的匹配项,它将不会搜索和捕获 some。我对hereherehere有一些解释。
【解决方案3】:

您可以尝试在出现 BEGIN 或 END 时拆分字符串,以确保您应用正则表达式的字符串中只有一个 BEGIN 和一个 END。此外,如果您正在寻找在您的 BEGIN/END 大括号之外出现的 SOME,那么我认为您会想在后面查找 END 并向前查找 BEGIN(正向向前/向后),这与您所拥有的相反。

希望这会有所帮助。

【讨论】:

    【解决方案4】:

    如果您只处理整个干草堆而忽略括号之间的干草会怎样(我是否将比喻推得太远了?)

    例如,查看所有标记(或字符,如果您需要进入该级别)并查找您的大括号。找到开始的括号后,循环遍历直到找到结束括号。那时,您开始寻找针头,直​​到找到另一个开口支架。它比正则表达式的代码多一点,但可能更易读且更容易排除故障。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-12-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-02
      • 1970-01-01
      相关资源
      最近更新 更多