【问题标题】:Example of "use \G in negative variable-length lookbehinds to limit how far back the lookbehind goes"“在负可变长度后视中使用 \G 以限制后视后退的距离”示例
【发布时间】:2015-02-18 04:40:38
【问题描述】:

在令人敬畏的正则表达式模块 (https://pypi.python.org/pypi/regex) 的 pypi 页面中,声明 \G 可用于“在负可变长度后视中以限制后视后退的距离”。非常有趣,但是该页面没有给出任何示例,当我尝试想象一个时,我的白带正则表达式只会窒息。

谁能描述一些示例用例?

【问题讨论】:

  • 我认为它是指(?<!\G\w*),或者类似的东西。
  • 好的,忍者已编辑,但它的概念有些相同......不过,我想不出任何用例。
  • 我仍然想知道为什么文档特别说“消极的lookbehind”,而不是简单的lookbehinds
  • (?<!...) 消极后视 (?<=..) 积极后视。如果有一个量词?*+ 存在于lookhehinds 中,那么它被称为可变长度正或负lookbehind。 (?<!\G\w*) 称为可变长度负后视,因为它有一个量词 *
  • @sln 老实说,过去几天我很忙,所以我无法花时间思考这个问题的解决方案/示例。由于这个问题“没有引起足够的关注”,我已经悬赏了。

标签: python regex


【解决方案1】:

下面是一个创造性地使用\G 和消极后视的例子:

regex.match(r'\b\w+\b(?:\s(\w+\b)(?<!\G.*\b\1\b.*\b\1\b))*', words)

words 应该是由一个空格分隔的字母数字字符串,例如"a b c d e a b b c d"

该模式将匹配一系列独特的单词。

  • \w+ - 匹配第一个单词。
  • (?:\s(\w+\b) )* - 匹配其他单词...
  • (?&lt;!\G.*\b\1\b.*\b\1\b) - ...但是对于添加的每个新单词,请检查它是否已经出现,直到我们到达 \G

限制在\G 的模式末尾的回溯可以断言当前匹配的另一个条件,否则这是不可能的。基本上,该模式是using lookaheads for AND logic in regular expressions 的变体,但不限于整个字符串。

这是 .Net 中的 working example,它具有相同的功能。
在 Python 2 中使用findallregex 模块尝试相同的模式会给我一个分段错误,但match 似乎有效。

【讨论】:

  • 对我来说不会崩溃(Python 3.4.1)但findall 返回['', '', '', '', '', ''] 这似乎没有用。 match 确实返回&lt;regex.Match object; span=(0, 9), match='a b c d e'&gt;,这很整洁!-)
  • 我认为使用\G 位置的lookbehind 在其第一个子表达式时有效。我认为最后一个(右侧)是不可行的。
  • 是的,你是对的,它只检查到当前的匹配位置。我有点困惑,以为是开放式的
【解决方案2】:

我能想到的一个例子是使用\Gpositive 后向以逗号分隔 CSV 行:

regex.split(r'(?<=\G(?:"[^"]*(?:""[^"]*)*"|[^"]*)),', csv)

这是一个变体,您只能使用可变长度的lookbehind 和\G

通常如果您想使用split,您可以在行尾添加一个前瞻,并检查以下记录是否都有效,例如,(?=([^\"]*\"[^\"]*\")*[^\"]*$)。这有点烦人,因为你一遍又一遍地匹配字符串的结尾。

我们也从未明确提及未加引号的值不是逗号 ([^,]),因为我们使用 \G 来匹配前一个逗号。

【讨论】:

  • 只是一个注释。拆分正则表达式只是验证下一个逗号在 dbl-quotes 之外。我不验证剩余报价的任何均匀性。第二个正则表达式(和链接)是一种非常糟糕的验证方式(如你所说),因为它就像一个 N 阶乘开销。如果需要验证,可以每行执行一次,然后在其上使用普通字段正则表达式,完全避免拆分。进行了基准测试和讨论 -> here.
  • [^"]*(?:""[^"]*)* 可以写成(?:[^"]|"")*。并且取决于引擎,它可以被占有。
  • @nhahtdh - 你是对的。我选择了unrolling-the-loop,没有想太多。 (?:[^"]|"")*+ 在这里可以很好地工作。
【解决方案3】:

这是一个可能比创意更有用的示例。
它使用从最后一个匹配开始的可变长度负向后查找 (\G)
向前检查到当前位置。

在这种情况下(?&lt;!\Ga+)b,结果是它匹配字符串中的每个其他b,其中b's 由一个或多个a's 分隔。

这也可以在像(?&lt;!\Ga)b 这样的固定宽度的lookbehind 中完成,结果是它匹配字符串中的所有其他b,其中b 的 由一个a 分隔。

这是一种模板,其中ab 可以是更大的表达式并且有更多
意义。

(需要注意的一点是,当在消极的后视中使用\G 时,很容易
满足否定断言。所以,这些东西都写满了gotcha!!

没有 Python(最新的,测试版?)来测试这个,所以下面是使用 C# 控制台应用程序。

string strSrc = "abaabaabaabaabaab";
Regex rxGtest = new Regex(@"(?<!\Ga+)b");
Match _m = rxGtest.Match(strSrc);
while (_m.Success)
{
    Console.WriteLine("Found: {0} at position {1}", _m.Groups[0].Value, _m.Index);
    _m = _m.NextMatch();
}

输出:

Found: b at position 4
Found: b at position 10
Found: b at position 16

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-08-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-11
    相关资源
    最近更新 更多