Perl正则表达式匹配较长句子中的可选短语

2023-12-09

我正在尝试匹配句子中的可选(可能存在)短语:

perl -e '$_="word1 word2 word3"; print "1:$1 2:$2 3:$3\n" if m/(word1).*(word2)?.*(word3)/'

Output:

1:word1 2: 3:word3

我知道第一个“.*”是贪婪的并将所有内容匹配到“word3”。使其变得非贪婪并没有帮助:

perl -e '$_="word1 word2 word3"; print "1:$1 2:$2 3:$3\n" if m/(word1).*?(word2)?.*(word3)/'

Output:

1:word1 2: 3:word3 

这里似乎存在利益冲突。我本以为 Perl 会匹配 (word2)?如果可能的话,仍然满足非贪婪的.*?。至少这是我对“?”的理解。 Perl 正则表达式页面显示“?”匹配 1 次或 0 次,那么它不应该更喜欢匹配一次而不是匹配 0 次吗?

更令人困惑的是,如果我捕获 .*?:

perl -e '$_="word1 word2 word3"; print "1:$1 2:$2 3:$3 4:$4\n" if m/(word1)(.*?)(word2)?.*(word3)/'

Output:

1:word1 2: 3: 4:word3

这里的所有组都是捕获组,所以我不知道为什么它们是空的。

只是为了确保词间空间没有被捕获:

perl -e '$_="word1_word2_word3"; print "1:$1 2:$2 3:$3 4:$4\n" if m/(word1)(.*?)(word2)?.*(word3)/'

Output:

1:word1 2: 3: 4:word3

鉴于唯一未捕获的匹配是 word2 和 word3 之间的匹配,我只能假设它是进行匹配的匹配。 果然:

perl -e '$_="word1_word2_word3"; print "1:$1 2:$2 3:$3 4:$4 5:$5\n" if m/(word1)(.*?)(word2)?(.*)(word3)/'

Output:

1:word1 2: 3: 4:_word2_ 5:word3

因此,贪婪匹配是向后进行的,Perl 很乐意匹配 word2 的零个(而不是一个)实例。使其变得非贪婪也无济于事。

所以我的问题是:如何编写正则表达式来匹配和捕获句子中可能的短语?我在这里给出的例子很简单;我正在解析的实际句子要长得多,我匹配的句子之间有很多单词,因此我无法假设中间文本的任何长度或组成。

非常感谢, 斯科特


背景:惰性量词和贪婪量词如何工作

您需要了解贪婪量词和惰性量词如何工作。贪婪的人会立即抓取他们的模式可以匹配的文本,然后引擎将回溯,即它会尝试回到贪婪量化子模式与子字符串匹配的地方,尝试检查下一个子模式是否可以匹配。

惰性匹配模式仅首先匹配最少的字符,然后尝试与其余子模式匹配。和*?, 它匹配zero字符,一个空格,然后继续检查下一个模式是否可以匹配,只有当不能匹配时,惰性子模式才会被“扩展”以包含另一个字符,依此类推。

So, (word1).*(word2)?.*(word3)将匹配word2与第一个.*(和第二个.*将匹配一个空格作为第一个.*是贪婪的。虽然你可以这样认为(word2)?是贪婪的,因此必须回溯到,答案是否定的,因为第一个.*抓住所有的绳子,然后引擎向后寻找匹配的东西。自从(word2)?匹配一个空字符串,它总是匹配的,并且word3从字符串末尾开始首先匹配。看这个演示并检查正则表达式调试器部分。

你想,让我们用与第一个的惰性匹配.\*?。问题在于(word1).*?(word2)?.*(word3)(匹配word2与第二个.*这是贪婪的)有点不同,因为它可以匹配可选组。如何?首先.*?匹配零个字符,然后尝试匹配所有后续子模式。由此,发现word1,然后是一个空字符串,以及没有找到word2就在之后word1. If word2就在之后word1,将会与第一个匹配.*?. See 这个演示.

SOLUTION

我现在看到两种解决方案,它们都包括使第二个可选组对于模式的其余部分“独占”,以便正则表达式引擎在找到它时无法跳过它。

  • A 分支重置 卡西米尔提供的解决方案多于。它的缺点是它无法移植到许多其他不支持分支重置的正则表达式风格。请参阅原始答案中的描述。
  • Use a 脾气暴躁的贪婪令牌: (word1)(?:(?!word2).)*(word2)?.*?(word3). It is 比分支重置解决方案效率低,但可以移植到 JS、Python 和大多数其他支持前瞻的正则表达式风格。这是如何运作的?(?:(?!word2).)*匹配 0 次以上出现的除换行符之外的任何字符(其中/s,甚至包括换行符)不开始文字字符序列word2. If w已匹配,后面不能跟ord2以使构造匹配。因此,当达到word2,它停止并让后续子模式 -(word2)?- 匹配并捕获以下内容word2. 为了使这种方法更加有效*, use 展开循环技术: (word1)[^w]*(?:w(?!ord2)[^w]*)*(word2)?.*?(word3).
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Perl正则表达式匹配较长句子中的可选短语 的相关文章

随机推荐

  • 在 iphone webView 中打开 .docx 的代码

    我是 iPhone 新手 我正在尝试在 UIwebView 中打开 docx 文件 我编写了以下代码 NSString urlAddress NSBundle mainBundle pathForResource Arabic litera
  • 为什么有些 PHP 安装有 $_SERVER['SCRIPT_URI'] 而其他安装没有?

    我运行两台 Apache 2 服务器 一个是 PHP5 2 另一个是 PHP5 3 5 3 机器上有什么原因吗 SERVER SCRIPT URI 这个变量从哪里来 它显然是来自 Apache 环境的东西 并且 PHP 手册中没有记录它 然
  • 对 Java 方法签名的完全限定引用

    是什么proper如何在 Java 中编写对方法名称的完全限定引用 Message com sun mail imap IMAPFolder addMessages Message Message com sun mail imap IMA
  • VueJS 手风琴表 - 出现在表之外

    我有一个表 其中使用 ajax 获取数据 我试图创建一个表 其中每行都有一个关联的隐藏行 单击该行可切换隐藏行的显示 隐藏行包含一个手风琴 问题是手风琴变得一团糟并显示在表格底部 而不是显示在它被单击的特定行下方 我的代码如下 table
  • 它将打印什么 console.log(1+ + "2")

    为什么这个 JavaScript 声明 console log 1 2 print 3 作为输出 我不知道为什么它会打印这个 我期望 12 or 字符串前面的操作数将其转换为数字 所以在这里 2 会变成2因此结果将是3 gt 1 2 2 2
  • Android 检测实际正在播放的铃声(Ringtone.isPlaying 问题)

    在 Android 上 我在尝试找出实际正在播放的铃声时遇到问题 我不是在尝试检测默认铃声 而是实际播放的铃声 因为由于用户为特定铃声设置了特定铃声 因此实际播放的铃声可能会有所不同 接触 当我循环浏览 成功 RingtoneManager
  • Spark 流不记得以前的状态

    我编写了带有状态转换的 Spark Streaming 程序 看来我的 Spark 流应用程序正在通过检查点正确地进行计算 但是 如果我终止程序并再次启动它 它不会读取之前的检查点数据并从头开始 这是预期的行为吗 我是否需要更改程序中的任何
  • 原生IOS设置远程视频描述发送参数失败

    这是 sdpOffer offer v 0 o 1514366952141741 1 输入 IP4hostx s 安装点 99 t 0 0 a 组 捆绑视频 a msid 语义 WMS janus m 视频 9 UDP TLS RTP SA
  • 将一个 TLD 的所有页面重定向到另一个 TLD

    今晚我简直要抓狂地想弄清楚这个问题了 我希望有人能帮助我 我的网站有 3 个 TLD 类似于以下内容 www domain com www domain org www domain net 它们都位于同一目录中 我想设置 301 重定向
  • PHP 开放时间 [关闭]

    Closed 这个问题需要细节或清晰度 目前不接受答案 我有一个客户想要一家在线披萨店 当然 他也不希望顾客在营业时间之后下订单 我为此制作了一个简单的脚本 我想我将来可能会与任何想要的人分享
  • DES、三重 DES、AES、河豚数据加密的比较

    有人比较这些加密算法的优缺点吗 Use AES 更详细地说 DES 是七十年代的旧 数据加密标准 它的密钥大小对于适当的安全性而言太短 56 个有效位 这可以被暴力破解 正如已经证明的那样十多年前 此外 DES 使用 64 位块 这在使用相
  • 使用 SharedPreferences 设置登录状态并在应用程序启动时检索它 - Flutter

    我有一个 flutter 应用程序 在该应用程序启动时我必须检查登录状态并相应地调用相关屏幕 用于启动应用程序的代码 class MyApp extends StatefulWidget override MyAppState create
  • 左外连接与 Entity Framework Core

    我正在尝试使用 EF7 7 0 0 rc1 final vNext RC1 rc1 final 和 SQL Server 2014 执行左外连接请求 数据库 宠物 身份证 姓名 用户 ID 姓名 PetId 这个有效 var queryWo
  • ASP.NET Core 中基于令牌的身份验证(已更新)

    我正在使用 ASP NET Core 应用程序 我正在尝试实现基于令牌的身份验证 但不知道如何使用新的保安系统 我的场景 客户端请求令牌 我的服务器应该授权用户并返回 access token 客户端将在以下请求中使用该令牌 这里有两篇关于
  • 具有格式相关类型的柯里化函数

    据我所知 F 不像处理其他函数那样处理 printfn 因为它依赖于字符串参数的类型 有人可以向我解释为什么这会阻止我这样做吗 let printn printfn A 该错误表示类型被推断为 a gt unit 我需要添加显式参数或类型注
  • 使用Friendly_id匹配单个Rails路线中的多个模型

    我有一个公司和一个用户模型 两者都有一个通过Friendly id 的slug 确保两种模型中的段头都是唯一的 我想要网址 http www example com any company name http www example com
  • Google 地图 API 路线

    我可以在应用程序中的谷歌地图上标记两个点 然后计算地图上的方向以及逐向导航吗 我正在创建一个应用程序 用于获取两点之间的行驶方向在地图上 一步一步 step1首先创建一个类MyOverlay java用于绘制路径 import androi
  • phpmyadmin 出现奇怪的错误,安装成功但仍然无法运行

    我一整天都在努力安装 phpmyadmin 我已经尝试重新安装很多次了 但还是不行 打开 localhost phpmyadmin 时 我收到一些文本 而不是实际的 phpmyadmin UI 正文是 addJSON options PMA
  • 如何在 Web midi api 中发现 midi 键盘?

    参考 2013 年的浏览器支持 Web MIDI API 我目前正在 OS 10 9 2 上运行 Chrome 34 0 1847 116 并尝试使用 Web Midi API 启用 chrome flags enable web midi
  • Perl正则表达式匹配较长句子中的可选短语

    我正在尝试匹配句子中的可选 可能存在 短语 perl e word1 word2 word3 print 1 1 2 2 3 3 n if m word1 word2 word3 Output 1 word1 2 3 word3 我知道第一