什么是正则表达式平衡组?

2023-11-21

我刚刚读到一个关于如何在双花括号内获取数据的问题(这个问题),然后有人提出了平衡组。我仍然不太确定它们是什么以及如何使用它们。

我通读了平衡组定义,但解释很难理解,而且我对我提到的问题仍然很困惑。

有人可以简单解释一下平衡组是什么以及它们有什么用处吗?


据我所知,平衡组是 .NET 的正则表达式风格所独有的。

旁白:重复组

首先,您需要知道 .NET 是(再次据我所知)唯一允许您访问单个捕获组的多个捕获的正则表达式风格(不是在反向引用中,而是在匹配完成后)。

为了通过示例来说明这一点,请考虑以下模式

(.)+

和字符串"abcd".

在所有其他正则表达式风格中,捕获组1只会产生一个结果:d(注意,完整的比赛当然是abcd正如预期的那样)。这是因为捕获组的每次新使用都会覆盖以前的捕获。

另一方面,.NET 会记住所有这些。它是在堆栈中执行的。匹配上面的正则表达式后

Match m = new Regex(@"(.)+").Match("abcd");

你会发现

m.Groups[1].Captures

Is a CaptureCollection其元素对应于四个捕获

0: "a"
1: "b"
2: "c"
3: "d"

其中数字是索引CaptureCollection。因此,基本上每次再次使用该组时,都会将新的捕获推入堆栈。

如果我们使用命名捕获组,事情会变得更有趣。因为 .NET 允许重复使用相同的名称,所以我们可以编写一个正则表达式,例如

(?<word>\w+)\W+(?<word>\w+)

将两个单词捕获到同一组中。同样,每次遇到具有特定名称的组时,都会将捕获推送到其堆栈上。因此将此正则表达式应用于输入"foo bar"并检查

m.Groups["word"].Captures

我们发现两个捕获

0: "foo"
1: "bar"

这使我们甚至可以将表达式的不同部分的内容推送到单个堆栈上。但这仍然只是 .NET 的功能,能够跟踪在此列出的多个捕获CaptureCollection。但我说过,这个系列是stack。那么我们可以pop东西来自吗?

输入:平衡组

事实证明我们可以。如果我们使用像这样的组(?<-word>...),然后从堆栈中弹出最后一个捕获word如果子表达式...火柴。因此,如果我们将之前的表达式更改为

(?<word>\w+)\W+(?<-word>\w+)

然后第二组将弹出第一组的捕获,我们将收到一个空的CaptureCollection到底。当然,这个例子没什么用。

但减号语法还有一个细节:如果堆栈已经为空,则该组将失败(无论其子模式如何)。我们可以利用这种行为来计算嵌套级别 - 这就是平衡组名称的来源(也是它变得有趣的地方)。假设我们想要匹配正确加括号的字符串。我们将每个左括号压入堆栈,并为每个右括号弹出一个捕获。如果我们遇到太多的右括号,它将尝试弹出一个空堆栈并导致模式失败:

^(?:[^()]|(?<Open>[(])|(?<-Open>[)]))*$

所以我们在重复过程中有三种选择。第一种选择消耗除括号之外的所有内容。第二个替代匹配(s 同时将它们推入堆栈。第三个替代匹配)s 同时从堆栈中弹出元素(如果可能的话!)。

Note: Just to clarify, we're only checking that there are no unmatched parentheses! This means that string containing no parentheses at all will match, because they are still syntactically valid (in some syntax where you need your parentheses to match). If you want to ensure at least one set of parentheses, simply add a lookahead (?=.*[(]) right after the ^.

但这种模式并不完美(或完全正确)。

结局:条件模式

还有一个问题:这并不能确保字符串末尾的堆栈为空(因此(foo(bar)将是有效的)。 .NET(以及许多其他风格)还有一种结构可以帮助我们解决这个问题:条件模式。一般语法是

(?(condition)truePattern|falsePattern)

哪里的falsePattern是可选的 - 如果省略,则 false-case 将始终匹配。条件可以是模式,也可以是捕获组的名称。我在这里将重点关注后一种情况。如果它是捕获组的名称,那么truePattern当且仅当该特定组的捕获堆栈不为空时才使用。也就是说,像这样的条件模式(?(name)yes|no)读作“如果name已匹配并捕获某些内容(仍在堆栈中),使用模式yes否则使用模式no".

因此,在上述模式的末尾,我们可以添加类似的内容(?(Open)failPattern)这会导致整个模式失败,如果Open- 堆栈不为空。使模式无条件失败的最简单的事情是(?!)(空的否定前瞻)。所以我们有了最终的模式:

^(?:[^()]|(?<Open>[(])|(?<-Open>[)]))*(?(Open)(?!))$

请注意,此条件语法本身与平衡组无关,但有必要充分利用它们的功能。

从这里开始,天空才是极限。许多非常复杂的用途都是可能的,并且与其他 .NET-Regex 功能(例如可变长度后向查找)结合使用时会出现一些问题(我必须自己努力学习)。然而,主要问题始终是:使用这些功能时您的代码仍然可维护吗?您需要很好地记录它,并确保每个使用它的人也都知道这些功能。否则,您可能会更好,只需手动逐个字符地遍历字符串并计算整数中的嵌套级别。

附录:怎么了(?<A-B>...) syntax?

这部分的功劳归于 Kobi(有关更多详细信息,请参阅下面他的回答)。

现在有了上述所有内容,我们可以验证字符串是否正确加括号。但如果我们能够真正获得所有这些括号内容的(嵌套)捕获,那么它会更有用。当然,我们可以记住在未清空的单独捕获堆栈中打开和关闭括号,然后在单独的步骤中根据它们的位置进行一些子字符串提取。

但是 .NET 在这里提供了一项更方便的功能:如果我们使用(?<A-B>subPattern),不仅从堆栈中弹出捕获B,还有弹出捕获之间的所有内容B并且当前组被推入堆栈A。因此,如果我们使用这样的组作为右括号,同时从堆栈中弹出嵌套级别,我们还可以将这对内容推送到另一个堆栈上:

^(?:[^()]|(?<Open>[(])|(?<Content-Open>[)]))*(?(Open)(?!))$

Kobi provided this Live-Demo in his answer

因此,将所有这些事情放在一起,我们可以:

  • 记住任意多次捕获
  • 验证嵌套结构
  • 捕获每个嵌套级别

全部都在一个正则表达式中。如果这不令人兴奋......;)

当我第一次了解它们时,我发现一些有用的资源:

  • http://blog.stevenlevithan.com/archives/balancing-groups
  • MSDN 关于平衡组
  • MSDN 关于条件模式
  • http://kobikobi.wordpress.com/tag/balancing-group/(有点学术性,但有一些有趣的应用)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

什么是正则表达式平衡组? 的相关文章

随机推荐

  • 如何将 DispatchTimeInterval 转换为 NSTimeInterval (或 Double)?

    我需要减去一个DispatchTimeInterval从一个NSTimeInterval or Double 有没有标准的方法来转换DispatchTimeInterval to an NSTimeInterval DispatchTime
  • 如何使 Flexbox 底部元素的内容为其容器的 100% 高度

    如果我制作一个具有 2 个子项和列流的 Flexbox 并将第二个子项设置为flex grow 1第二个子项扩展以填充弹性盒 这有效 ps 不想让示例与 safari 支持变得混乱 所以使用 Chrome 或 Firefox box siz
  • 广播意图回调:result=CANCELLED forIntent

    我有一个移动应用程序 它注册到 c2dm 服务器 我有一个服务器向我的应用程序发送消息以推送通知 服务器从 google c2dm 接收到 ok 结果代码 在 LogCat 中 我看到我的应用程序收到了消息 但立即产生了我在帖子中遇到的错误
  • Google Apps 脚本的 Jdbc 连接错误

    我创建了一个 Google Cloud Project MySQL 数据库 与 Google Apps 脚本提供的 Jdbc 服务结合使用 连接一切都按计划进行 我基本上按照文档中的方式进行连接 var conn Jdbc getCloud
  • 创建网站的移动版本

    我正在寻找创建我们网站 网络应用程序的移动版本 有什么好方法可以提供最好的 功能最全的版本 创建它的部分原因是而不是 iPhone 应用程序 所以我想提供一个 iPhone Web 应用程序 充分利用 iPhone 版本的 WebKit 因
  • 嵌套 if 语句和“&&”运算符

    if a b c d doSomething if a if b if c if d doSomething 这两者之间有 任何 性能差异吗 例如 当a 变为0的情况下 它会继续运行第一个if语句中的b c 和d 吗 或者它的工作方式与第二
  • c 中右值存储在哪里?

    在C中 我有这段代码 int a a 10 5 3 我想问 10 5 3 存放在哪里 据我所知 a位于堆栈上 怎么样 10 5 3 这个右值是如何计算的 通常 右值 存储 在程序本身内 换句话说 编译器本身 在程序运行之前 计算 10 5
  • 为CDK中的资源添加条件

    我创建了一个将部署在多个区域的 CDK 堆栈 其中一个构造只能部署在一个区域 在 Cloudformation 中 我只需向资源添加一个条件 但我还没有找到一种方法来对 CDK 构造执行类似的操作 可以定义一个CfnCondition并将其
  • 精确控制 GLSL 中的纹理位

    我正在尝试使用 OpenGL 和 GLSL 实现八叉树遍历方案 并且希望将数据保留在纹理中 虽然纹理数据有多种格式可供选择 不同大小的浮点数和整数 但我在弄清楚是否有一种方法可以更精确地控制位 从而实现更高的效率和紧凑的存储方面遇到了一些麻
  • 如何计算jquery中mousedown事件期间的时间?

    我试图在 mousedown up 事件上的一个按钮上执行 2 个不同的功能 但它不起作用 因为我无法检测 mousedown 事件的时间 var flag ClikerButton mousedown function e if mous
  • 获取目录中文件的数量

    如何统计目录中的文件数 我在类参考中找不到任何相关内容NSFileManager contentsOfDirectoryAtPath error 返回一个NSArray 只需发送count到数组
  • LLDB (Swift):将原始地址转换为可用类型

    是否有一个 LLDB 命令可以将原始地址转换为可用的 Swift 类 例如 lldb po 0x7df67c50 as MKPinAnnotationView 我知道这个地址指向 MKPinAnnotationView 但它不在我可以选择的
  • 为什么 pandas DataFrame 可以互相改变?

    我试图保留 pandas DataFrame 的副本 以便我可以在保存原始数据的同时对其进行修改 但是当我修改副本时 原始数据框也会发生变化 前任 df1 pd DataFrame col1 a b c d col2 1 2 3 4 df1
  • onCompleted 可以与 useMutation 一起使用吗?

    我在 React 项目中使用 useMutation 钩子 突变运行成功 但之后未达到 onCompleted 我已在突变中将notifyOnNetworkStatusChange 设置为true 但这似乎没有帮助 const create
  • OnClickListener - 事件的 x,y 位置?

    我有一个从 View 派生的自定义视图 我希望在单击视图时收到通知 以及单击发生的 x y 位置 长按也是如此 看起来像这样做 我需要覆盖onTouchEvent 有没有办法从事件的 x y 位置OnClickListener相反 但是 如
  • map_partitions的返回值是多少?

    dask API 表示 map partition 可用于 在每个 DataFrame 分区上应用 Python 函数 根据此描述并根据 map 的通常行为 我期望 map partitions 的返回值是 类似于 一个长度等于分区数量的列
  • 找出最新术语和第二个最新术语之间的差异

    表的结构就像 create table events event type integer not null value integer not null time timestamp not null unique event type
  • Flutter 无法从剪贴板读取

    我来询问一个关于 Flutter 和 Future 的非常具体的问题 并等待机制 这似乎有效 但我的剪贴板在使用可编辑文本字段操作时并没有真正起作用 即使遵循 Google 关于实现的建议 这是我的粘贴代码 onPressed async
  • 如何在 IE(9+) 和 Safari (Pad) 中播放带有 HTML5 音频的 .m4a?

    我需要在 IE 9 和 Safari iPad iPhone 中播放 m4a 文件 在 iPhone 上录制 我在设置正确的 MIME 类型时遇到问题 为了在 IE10 中播放 我需要设置audio mp4但对于 Safariaudio a
  • 什么是正则表达式平衡组?

    我刚刚读到一个关于如何在双花括号内获取数据的问题 这个问题 然后有人提出了平衡组 我仍然不太确定它们是什么以及如何使用它们 我通读了平衡组定义 但解释很难理解 而且我对我提到的问题仍然很困惑 有人可以简单解释一下平衡组是什么以及它们有什么用