【问题标题】:match all commas that are outside parentheses and square brackets in perl regex匹配 perl 正则表达式中括号和方括号之外的所有逗号
【发布时间】:2021-09-19 02:00:55
【问题描述】:

我正在尝试使用正则表达式匹配所有逗号(后跟一个空格):, 在任何括号或方括号之外,即逗号不应包含在括号或方括号中。

目标字符串是A, An(hi, world[hello, (hi , world) world]); This, These。在这种情况下,它应该匹配第一个逗号和最后一个逗号(AAnthisthese 之间的逗号)。

所以我可以将A, An(hi, world[hello, (hi , world) world]); This, These 拆分为AAn(hi, world[hello, (hi , world) world]); ThisThese,而不会导致括号/括号不平衡。

为此,单独使用正则表达式似乎很困难。有没有其他方法可以解决这个问题?

我正在使用的正则表达式: , (?![^()\[\]]*[\)\]])

但是这个表达式会匹配另外两个不应该匹配的逗号, (第二个和第三个)。

虽然如果它与以下字符串匹配,它将匹配正确的逗号(分别为第一个):A, An(hi, world)A, An[hi, world]

但是如果括号和方括号相互包含,那就有问题了。

此链接中的更多详细信息: https://regex101.com/r/g8DOh6/1

【问题讨论】:

  • 必须单独使用正则表达式吗?使用Text::Balanced(例如)可以提取平衡的括号/括号和其余部分,然后从“其余部分”中选择逗号。
  • @zdim 我已经更新了帖子。不一定是单独的正则表达式。任何事情都可以解决问题。
  • 好的,谢谢!所以......你想要最终的结果是什么? those_commas 之前的单词(没有逗号)?请查看我的答案并告诉我(我会编辑更多)——它解决了问题,但我不知道实际的_result 应该是什么!
  • 目的是将目标字符串与外面的逗号分开,假设目标字符串为B, C, hello(D,) world,预期输出为BChello(D,) world
  • 所以我可以继续最后一步:将hello(D,) world 变成hello world。不过,这篇文章不是关于这最后一步。更多的是为最后一步做准备。

标签: regex perl


【解决方案1】:

这里的问题是在这种情况下识别括号/括号的“平衡”对。这是一个公认的问题,为此有图书馆。他们可以找到顶级匹配对,(...)/[...] 与内部的所有内容,以及括号之外的所有其他内容 - 然后处理“其他”。

一种方式,使用Regexp::Common

use warnings;
use strict;
use feature 'say';

use Regexp::Common;

my $str = shift // q{A, t(a,b(c,))u B, C, p(d,)q D,}; 

my @all_parts = split /$RE{balanced}{-parens=>'()[]'}/, $str;

my @no_paren_parts = grep { not /\(.*\) | \[.*\]/x } @all_parts;

say for @no_paren_parts;

这使用 split 的属性返回包含分隔符的列表,当分隔符模式中的正则表达式捕获时。library regex 捕获所以我们将其全部取回 - 部分通过根据正则表达式匹配的内容以及正则表达式匹配的部分拆分字符串来获得。分隔符包含成对的分隔符,而其他术语则不能,通过构造,因此我将它们过滤掉。打印

在 u B, C, p q D,

括号/括号术语已经消失,但是字符串的拆分方式有点随意。

以上内容有点“通用”,使用库仅提取平衡对()/[],以及字符串的所有其他部分。或者,我们可以从字符串中删除这些模式

$str =~ s/$RE{balanced}{-parens=>'()[]'}//g;

留下来

A, 你 B, C, pq D,

现在可以简单地用逗号分隔

my @terms = split /\s*,\s*/, $str;
say for @terms;

一个 涂乙 C pq D

这是在这种情况下所期望的结果,正如 cmets 中所阐明的那样。

另一个最著名的库,在许多方面更基本,是核心Text::Balance。请参阅此处的Shawn's answer,例如this postthis onethis one 示例。


一个例子。与

my $str = q(it, is; surely);

my @terms = split /[,;]/, $str;

一个在数组@terms中得到itissurely,而与

my @terms = split /([,;])/, $str;

我们进入@terms所有:it,is;surely


同样通过构造,它包含正则表达式在偶数索引处匹配的内容。所以对于所有其他部分,我们可以获取奇数索引处的元素

my @other_than_matched_parts = @all_parts[ grep { not $_ & 1 } 0..$#all_parts ];

【讨论】:

  • 感谢您的回答。一个问题,假设目标字符串是A, t(a,b(c,)) B, C, u(d,) D,,答案的结果将是A, tB, C, uD,,其中uD 是分开的。它们能合二为一吗? uD?在字典数据中,go about, go (a)round, 之类的短语很常见。我想将它们提取为go aboutgo round
  • 对于A, t(a,b(c,)) B, C, u(d,) D,,输出应该是A, tB, C, u D,
  • @jonah_w 好的,现在得到它——毕竟逗号仍然存在,只需删除 (...)。那么 - 输出应该是一个数组,就像答案的第一部分一样? (不是第二部分中的一个字符串吗?)
  • @jonah_w 所以......我的答案第一部分的输出正是你所需要的,不是吗?包含元素的数组:A, tB, C,u D,(从答案复制粘贴,第一部分)
  • @jonah_w 请注意,您可以将输入输入到上面的程序中,prog.pl "....."(这就是开头的 shift // ... 所做的——如果输入字符串包含空格,您确实需要在输入字符串周围加上引号) .因此,当我在问题中的示例字符串上运行它时,最终输出(来自第二部分)是:AAn; ThisThese
【解决方案2】:

检查逗号 , 是否在括号/括号内,例如

[(,),],[abc,(def,[ghi,],),],[(,),]
      ^                    ^

意味着模式必须知道这些括号/括号中的每一个何时以平衡的方式打开和关闭,所以不仅仅是[([],因为它应该是[([])]

这是一个替代解决方案,它不能直接解决您的问题,但可能更接近一步。

  1. 符合以下任一条件:

    一个。逗号

    b.包含在外部[]() 中的组。见Regular expression to match balanced parentheses

  2. 过滤掉 1.b

正则表达式模式:

(?:\((?>[^()]|(?R))*\)|\[(?>[^\[\]]|(?R))*\]|,)

对于这个字符串,匹配项如下所示:

A, An(hi, world[hello, (hi , world) world]) and this, is that, for [the, one (in, here, [is not,])] and last,here!
 ^   ^------------------------------------^         ^        ^     ^------------------------------^         ^
  • 因此它没有捕获任何括号/括号组内的任何逗号,因为它捕获了它们作为一个整体。现在,您在外层有了逗号。

【讨论】:

    【解决方案3】:

    zdim 提到的一种方法是使用核心Text::Balanced 模块。示范:

    #!/usr/bin/env perl
    use strict;
    use warnings;
    use feature qw/say/;
    use Text::Balanced qw/extract_bracketed/;
    
    my $str = "A, An(hi, world[hello, (hi , world) world]); This, These";
    my ($inside, $after, $before) = extract_bracketed $str, '()[]', qr/[^([]*/;
    
    my @tokens = (split(/,/, $before//""), $inside, split(/,/, $after//""));
    
    # Displays
    # A  An (hi, world[hello, (hi , world) world]) ; This  These
    say join(' ', @tokens);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多