【问题标题】:regex to ignore patterns when after a given characterr正则表达式在给定字符之后忽略模式
【发布时间】:2017-02-12 23:21:31
【问题描述】:

我正在尝试发现一种模式(在 Ruby 源代码文件中),但如果在内联注释中找到该模式(即在 # 字符之后),则忽略该模式。

例如,给定这个文本 foo.bar foo foo::bar # foo.bar foo::bar

我希望捕获foo 的第一个 (foo.bar) 和第三个 (foo::bar) 案例,其余的忽略(第二个没有立即尾随 .:: , 第四个和第五个出现在# 之后,所以应该忽略。

对于这个文本, foo.bar foo foo::bar

它仍然应该以相同的方式拾取第一个和第三个(因为没有评论可以忽略)。

我有各种技术可以解决这个问题,但没有一个能满足所有情况。 Lookbehind 很有希望,但无法在我的正则表达式方言(Ruby)中处理可变长度。

因此,((?<!\#.*)foo[\.|:{2}]) 不起作用,因为它是可变长度的(并且,正如所写,无论如何只会排除 # 之后的第一个实例)

(.+?(?=#)) 也很有希望,所以我尝试了((foo(\.|\:{2})).+)?(?=\#),这很接近,但看不出有 2 个 foos 在第一个之后。匹配组只返回foo.bar foo foo::bar,但它会适当地忽略# 之后的任何内容。我很确定是 .+ 造成了不好的区别,但对此的其他修改似乎并没有让我更接近。

显然,我不知道该怎么做,并开始怀疑这是否可能。

[编辑:添加第二个例子]

【问题讨论】:

    标签: regex regex-negation regex-lookarounds regex-greedy


    【解决方案1】:

    我不在 Ruby 中工作,但根据您的描述,听起来 Ruby 不支持后视中的无限量词。这肯定会让事情变得更加困难。但是,您可以利用无限前瞻。您可以使用正则表达式来检查没有内联 cmets 的 foo_bars:

    ^[^#]*foo(?:\.|::)bar(?=[^#]*$)
    

    ...还有一个正则表达式,用于检查具有内联 cmets 的 foo_bars:

    foo(?:\.|::)bar(?=[^#]*#)
    

    ...然后将它们交替放置在一起:

    foo(?:\.|::)bar(?=[^#]*#)|^[^#]*foo(?:\.|::)bar(?=[^#]*$)
    

    【讨论】:

    • 好主意!我让这两个案例分开工作,但没有想到将这样一个“大”对放在一起的交替。我会试试的,谢谢!
    • 你做了一件事我想确保我理解。两个子句中的?=[^#]* 是为了确保在$ 或第一个# 之前没有遇到评论,对吗?我试过?=.*#,但捕获的太多了。我还为以下部分尝试了*[$|#],但它也不起作用。您能否再解释一下或将我引导至适当的资源?谢谢!
    • 正确。点星是有问题的,因为点匹配任何东西,“任何东西”包括#。您可以通过使用非贪婪的点星 (.*?) 来缓解这种情况。 “不散列”或非贪婪的点星应该工作 - 这是一个问题或偏好。
    • 好的,这是有道理的——我需要更方便地处理贪婪的行为。所以要捕获,我只需要将 foo 括在括号中,但后来我注意到,如果没有内联注释,捕获不能用于获取单个实例(使用 (foo)(?:\.|::)bar(?=[^#]*#)|^[^#]*(foo)(?:\.|::)bar(?=[^#]*$)
    • 我不熟悉 Ruby 的正则表达式实现。您需要查阅文档以了解捕获组的工作方式。在我使用的引擎中,您通常会从引擎中获取所有捕获组,但未参与比赛的捕获组将是空的。请记住,(AFAIK)捕获组是从左到右的编号,嵌套组在最右边的组之前编号。因此,在您的模式中,第一个 (foo) 是捕获组 1,第二个 (foo) 是捕获组 2。无论哪个匹配,它们仍然分别是 1 和 2。
    猜你喜欢
    • 2014-03-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-06
    • 1970-01-01
    相关资源
    最近更新 更多