【问题标题】:Regular Expression Lookbehind Issue正则表达式 Lookbehind 问题
【发布时间】:2013-11-24 18:55:00
【问题描述】:

我正在尝试编写一个正则表达式来从我正在构建的项目中保存的历史文件中提取文本块。目前我正计划在我的文本编辑器(textmate 或 sublimetext 2)中手动进行此提取,但最终我将使用 python 或 php(尚未决定)将其构建到脚本过程中。

我的历史文件中的所有历史条目都具有以下格式:

YYYY-MM-DD - Chris -- Version: X.X.X
====================================
- Lorem ipsum dolor sit amet, vim id libris epicuri
- Et eos veri quodsi appetere, an qui saepe malorum eloquentiam.
...

--

其中 X 是工作的版本号。

我正在尝试将所有内容从版本号拉到最后的双破折号分隔符,它表示文本块的结尾。

我首先创建了正则表达式语句来选择有效的部分标题:

(^[\d]{4}-[\d]{2}-[\d]{2}\s-\s[\w]+\s--\sVersion:\s)[\d\.]+$

但是当我尝试将括号中的模式转换为它背后的外观时失败了:

(?<=^[\d]{4}-[\d]{2}-[\d]{2}\s-\s[\w]+\s--\sVersion:\s)[\d\.]+$ 

我一直在环顾四周,到目前为止,这种lookbehind 格式似乎是正确的。我似乎无法弄清楚我错过了什么。有什么想法吗?

【问题讨论】:

  • Lookbehind 几乎从不这样使用。
  • 知道了,我想这是极少数情况之一;)
  • 我说几乎从不,因为你可以简单地捕捉你想要的东西,而不用从匹配中排除任何东西,所以你不使用它来强制执行条件。您正在使用它来排除不必要的匹配(组 0)。
  • 啊,好的。根据您的第一条评论,我没有意识到这就是您的意思。我想我仍然有点模糊为什么我不想按照我概述的方式去做。如果该语句表示一个文本块的开始,那么除了版本号之外我什么都不想要,并且除了该字符串匹配之外,没有真正不同的方式来告诉特定块从哪里开始,为什么要我还想在后面的look中包含字符串?
  • 这里是一个例子,不要往后看:$string = "2013-11-25 - Chris -- Version: 2.1.7\nwhat-1\n--\n2013-11-25 - Fred -- Version: 2.1.7\nwhat-2";$count = preg_match_all('/^\d{4}-\d{2}-\d{2}\s-\s(\w+)\s--\sVersion:\s([\d\.]+)(.*?)(?:^--|(?![\S\s]))/sm',$string,$matches);for($i=0;$i&lt;$count;$i++){ print ( "who=" . $matches[1][$i] . "\n" ); print ( "vers=" . $matches[2][$i] . "\n" ); print ( "what=" . $matches[3][$i] . "\n----------\n" );}

标签: php python regex lookbehind


【解决方案1】:

正如Joey 所说,在 php 或 python 中没有任意长度的lookbehind。但是 PHP 中有一个解决方法! \K 转义序列。

来自docs

转义序列 \K 导致任何先前匹配的字符不 被包含在最终匹配的序列中。例如模式:

   foo\Kbar

匹配“foobar”,但报告它匹配“bar”。此功能 类似于后向断言(如下所述)。然而,在这种情况下,真正匹配之前的主题部分不必是固定长度的,就像后向断言所做的那样。

删除一些多余的括号[]后,你的表达式看起来像

(?m)^\d{4}-\d{2}-\d{2}\s-\s\w+\s--\sVersion:\s\K[\d.]+$

Online demo

注意事项:

  • (?m) :是内联 regex modifier
  • 您无需在字符类中转义点 .[.] 将匹配点而不是任何字符
  • 您可以在空白字符中添加一些量词:\s*\s+
  • \w+ 也将匹配下划线_,因此您可以使用[^\W_]+ 排除它
  • 正则表达式 真棒

【讨论】:

  • 太棒了!感谢您添加注释和修改后的声明。我对正则表达式还是很陌生(我上周开始研究它)所以很高兴看到可以省略的冗余和注意事项。还要感谢 regex101.com 的链接。我不知道这个网站存在。这将是一个巨大的帮助在未来。
  • @ChrisSchmitz 加入regex chatroom 以获取更多提示和技巧,您甚至可以讨论您的正则表达式问题
  • 很好,感谢另一个有用的链接。我需要花一些时间进一步探索 stackoverflow。我什至没有意识到有聊天室:P
【解决方案2】:

PHP 和 Python 都不允许任意长度的后视。所以只要你有一个像+ 这样的量词,它就会停止工作。

所以你的第一次尝试是唯一可行的方法。

【讨论】:

  • 太棒了!知道我无法进行可变长度的后视,我将标题格式更改为YYYY-MM-DD - Version: X.X.X - Chris,并将我的声明更改为(?&lt;=^[\d]{4}-[\d]{2}-[\d]{2}\s-\sVersion:\s)([\d\.]+\s-\s[\w]+)$。这样,我对数据的所有看法都是固定宽度。这实际上提供了解析我(或其他开发人员之一)名称以使用它的额外好处。感谢您的帮助!
猜你喜欢
  • 2012-02-08
  • 2021-05-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多