【问题标题】:regex only match content outside all kinds of brackets正则表达式只匹配各种括号外的内容
【发布时间】:2021-01-23 00:01:28
【问题描述】:

对于这个字符串:hello (hi that [is] so cool) awesome {yeah} 我希望正则表达式只匹配 helloawesome

这是我迄今为止尝试过的,它似乎不起作用。 https://regex101.com/r/NsUfQR/1

([^\(\)\[\]\{\}[]()〔〕〈〉【】]+)(?![^()\[\]\{\}[]()〔〕〈〉【】]*[\)\])〕〉】]])

这匹配 hello hi that awesome yeah 太多了。

是否可以仅使用正则表达式来实现这一点,或者使用 perl 或 python 是否有另一种方法?

【问题讨论】:

  • 先到先得?也嵌套?平衡文字 ?说outside意味着更多。
  • 是的,括号,它们可以相互嵌套。目的是不管哪个括号在最外面,里面的东西都不匹配。
  • 这就是为什么我说先到先得。我的意思是如果内部文本是 unbalanced 没关系,即here (not[here]]or there) ok。你用的是 Perl 还是 Python?
  • 我正在使用 Perl。 Perl 更可取。 :)

标签: python regex perl


【解决方案1】:

这涉及到处理匹配分隔符的棘手事务,可能是嵌套的。

我建议不要纠结一个盛大的正则表达式,而是使用核心 Text::Balanced 解析所有平衡(顶级)括号对之外的文本字符串,这正是问题中描述的内容。

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

use Text::Balanced qw(extract_bracketed);

my $string = 'hello (hi that [is] so cool) awesome {yeah}';

my @outside_of_brackets;

my ($match, $before);
my $remainder = $string;
while (1) {
    ($match, $remainder, $before) = extract_bracketed(
        $remainder, '(){}[]', '[^({[]*'
    );
    push @outside_of_brackets, $before // $remainder;
    last if not defined $match; 
}

say for @outside_of_brackets;

我们要求查找任何给定括号的第一个顶级对的内容, 并且随之我们得到该对 ($remainder) 之后的内容以及之前的内容它。

这里需要的是$before,我们继续以同样的方式解析$remainder,选择$before,直到没有更多的匹配;此时$remainder 中没有括号,因此我们也采用它(此时$before 也必须为空)。

代码得到预期的字符串,带有一些额外的空格;根据需要修剪。

有关另一个示例以及使用Regexp::Common 的另一种方法,请参阅this post


extract_bracketed 提取第一对顶级平衡括号中的内容,默认情况下需要在字符串的开头(可能的空格之后)或紧跟在上一场比赛结束;或者,在第三个参数(如果给定)中的模式之后,然后 必须 找到(因此这里的 * 量词,以防括号 在开头)。

所以在这种情况下,它会跳到第一个左括号,然后 然后 解析字符串以寻找平衡的括号对。要查找的括号类型作为其第二个参数给出。

【讨论】:

    【解决方案2】:

    这个正则表达式只使用普通的文本括号 (),[],{}
    您可以添加自己的,只需复制一个块,粘贴它并更改分隔符
    你想要的括号。注意递归组。
    在排除列表中添加前括号。
    另请注意,最后通过[\S\s] 跌落以捡起任何流浪者。

    更新添加了所有括号类型(来自评论)。

    /(?:[^\(\[{〈【〔([]+|(?:(\((?>[^()]++|(?1))*\))|({(?>[^{}]++|(?2))*})|(\[(?>[^\[\]]++|(?3))*\])|(〈(?>[^〈〉]++|(?4))*〉)|(【(?>[^【】]++|(?5))*】)|(〔(?>[^〔〕]++|(?6))*〕)|(((?>[^()]++|(?7))*))|([(?>[^[]]++|(?8))*]))(*SKIP)(*FAIL)|[\S\s])/
    https://regex101.com/r/LUXJVu/1

     (?:
        [^\(\[{〈【〔([]+ 
      | 
        (?:
           (                   # (1 start), Left/Right parenthesis
              \(    
              (?>
                 [^()]++ 
               | (?1) 
              )*
              \)                     
           )                   # (1 end)
         | 
           (                   # (2 start), Left/Right curly bracket
              {
              (?>
                 [^{}]++ 
               | (?2) 
              )*
              }
           )                   # (2 end)
         | 
           (                   # (3 start), Left/Right square bracket
              \[ 
              (?>
                 [^\[\]]++ 
               | (?3) 
              )*
              \] 
           )                   # (3 end)
         | 
           (                   # (4 start), Left/Right angle bracket
              〈
              (?>
                 [^〈〉]++ 
               | (?4) 
              )*
              〉
           )                   # (4 end)
         | 
           (                   # (5 start), Left/Right black lenticular bracket
              【
              (?>
                 [^【】]++ 
               | (?5) 
              )*
              】
           )                   # (5 end)
         | 
           (                   # (6 start), Left/Right tortoise bracket
              〔
              (?>
                 [^〔〕]++ 
               | (?6) 
              )*
              〕
           )                   # (6 end)
         | 
           (                   # (7 start), Left/Right fullwidth parenthesis
              (
              (?>
                 [^()]++ 
               | (?7) 
              )*
              )
           )                   # (7 end)
         | 
           (                   # (8 start), Left/Right fullwidth square bracket
              [
              (?>
                 [^[]]++ 
               | (?8) 
              )*
              ]
           )                   # (8 end)
        )
        (*SKIP) (*FAIL) 
      | 
        [\S\s] 
     )
    

    【讨论】:

    • 在我添加了其余的括号后,并在 perl 单行中进行了测试:perl -E'$a="hi (hello) world"; @test = $a =~ /((?:[^\(\[\{〈【〔([]+|((\((?>[^()]++|(?1))*\))|(\{(?>[^\{\}]++|(?2))*\})|(\[(?>[^\[\]]++|(?3))*\])|(〈(?>[^〈〉]++|(?4))*〉)|(【(?>[^【】]++|(?5))*】)|(〔(?>[^〔〕]++|(?6))*〕)|(((?>[^()]++|(?7))*))|([(?>[^[]]++|(?8))*])|)(*SKIP)(*FAIL)|[\s\S]))/g; say for@test;' 似乎只打印了一个hi,应该是hiworld。还是我写错了?
    • 它可以在regex101.com/r/oFFSoa/2 上运行。只是不能在 perl 单行中工作。
    • @jonah_w 正则表达式中的捕获组有点变形了。请参阅更新以获得更好的正则表达式。
    【解决方案3】:
    my $string = 'hello (hi that [is] so cool) awesome {yeah} <and <then> some (even {more})>';
    1 while $string =~ s/\([^(]*?\) *//;  #remove all ()
    1 while $string =~ s/\[[^\[]*?\] *//; #remove all []
    1 while $string =~ s/\{[^{]*?\} *//;  #remove all {}
    1 while $string =~ s/<[^<]*?> *//;    #remove all <>
    print "What is left now: $string\n";  #hello awesome
    

    或一体机:

    1 while $string=~s/( \([^(]*?\) | \[[^[]*?\] | \{[^{]*?\} | <[^<]*?>  ) \s*//xg;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-09-06
      • 2016-02-13
      • 2020-11-25
      • 2011-07-18
      • 2012-01-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多