免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 46102 | 回复: 19
打印 上一主题 下一主题

正则表达式能否捕捉多重括号中对等括号中的内容? [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2016-08-02 15:04 |只看该作者 |正序浏览
本帖最后由 hztj2005 于 2016-08-02 15:05 编辑

正则表达式能否捕捉对等括号中的内容?
100-( 5*(4+89-(34/5)))

我的意思是能否捕捉: -号后的 ( 5*(4+89-(34/5)))
                             *号后的(4+89-(34/5))

谢谢!

论坛徽章:
0
20 [报告]
发表于 2016-08-28 12:55 |只看该作者
#这个实现简捷
#!/usr/bin/perl -w
#use strict;
use Data:umper;

my $expr = '((A,B),C,(D,E))';
print extract2('C',$expr),"\n";
print extract2('B',$expr),"\n";
print extract2('D',$expr),"\n";

sub extract2 {
    my $char = shift;
    my ($str,$dup) = (shift) x 2;
    1 while $dup =~ s/\([^()$char]*\)/'.' x length $&/e;
    print $dup."\n";#转帖时添加,便于寻究其思路
    $dup =~ m/(\([^()$char]*$char[^()]*\))/;
    return substr($str,$-[1],length $1);
}


exit;

论坛徽章:
0
19 [报告]
发表于 2016-08-28 12:37 |只看该作者
本帖最后由 hztj2005 于 2016-08-28 12:39 编辑

这个方法的输出比较直观:
This is probably a klunky solution, but it reminded me of a parser I had written.. (Evaluate Expressions.)

Quickly hacking at it and only testing a few simple cases (you've been warned)

You could use the returned structure to search for whatever criteria you desire. I'm sure someone here has a much more elegant solution, but my regex abilities are rather limited...

use warnings;
#use strict;
use Data:umper;
my $input = '(a,b,(c,d,(e,f,g)))';

print Dumper parse_expression($input);

sub parse_expression {
    my $exp = shift;
    my @tokens = ();
    $exp=~s/\s*([()])\s*/ $1 /go;
    # Get tokens
    push @tokens, $1 while $exp=~/\G\s*(".*?"/gc or $exp=~/\G\s*('.*?')/gc or $exp=~/\G\s*(\S+)/gc;
   
    # Find any parens.
    my (@lp,@rp) = ();
    for (my $p =0; $p < @tokens; $p++){
        if ($tokens[$p] eq '('){
            push @lp,$p;
        }elsif($tokens[$p] eq ')'){
            push @rp,$p;
        }
    }
   
    if ( @lp != @rp){
        warn "Mismatched parens in expression.\n";
        return;

    }

    my @temp = @tokens;
    for (my $i=0; $i < @rp; $i++){
         my @wanted;
         for (my $j = $#lp; $j >= 0 ; $j--)
         {
            if ( defined $lp[$j] && $lp[$j] < $rp[$i] )
            {
                (undef,@wanted) = @tokens[ $lp[$j] ..  ($rp[$i] - 1 ) ] ;   
                @tokens[ $lp[$j] ..  ($rp[$i]) ] = [ grep {defined $_ } @wanted];
                push @temp, map {split /\s*,\s*/} @wanted;
                $lp[$j] = $rp[$i] = undef;
                last;
            }
         }
    }

  return $tokens[0];

}

# OUTPUT
$VAR1 =
          [
            'a,b,',
            [
              'c,d,',
              [
                'e,f,g'
              ]
            ]
          ];

论坛徽章:
0
18 [报告]
发表于 2016-08-28 12:03 |只看该作者
转自perlmonks.org/?node_id=308039,一般程序实现:

#Here is a simple way to do it by keeping track of how deep you are into parenthesis' and what depth your match occured at:
use strict;
my $str = "((A,B),C,(D,E))";
foreach my $m (qw(A B C D E)) {
  print $m." => ".FindMinParens($m,$str)."\n";
}
sub FindMinParens
{
  my $match = shift;
  my $string = shift;
  my @start_pos;
  my $depth = -1;
  # keep matching parens or $match
  while ($string=~/([()]|$match)/g) {
    if ($1 eq "(") {
      # record opening paren positions
      push @start_pos,pos($string);
    }
    elsif ($1 eq ")") {
      # if we reached the closing parens for the minimum pair
      # get the sub string and exit
      if ($#start_pos == $depth) {
        my $start = $start_pos[-1];
        my $len = pos($string) - $start -1;
        return substr($string,$start,$len);
      }else{
        pop @start_pos;
      }
    }
    else {
      # store depth of $match
      $depth = $#start_pos;
    }
  }
  return "";
}

exit;

论坛徽章:
0
17 [报告]
发表于 2016-08-28 11:50 |只看该作者
本帖最后由 hztj2005 于 2016-08-28 12:03 编辑

转自perlmonks.org/?node_id=308039,用Regexp::Common模块实现:


use Regexp::Common;

my $balanced = qr/[^()]+|$RE{balanced}{-parens=>'()'}/;

sub extract {
    my ($want, $from) = @_;
    my $nested = qr/$balanced* \Q$want\E $balanced*/x;
    $from =~ m/( \( $nested \) | \Q$want\E )/x;
    return $1;
}

my $expr = '(((B,G),A,(A,B)),C,(D,(E))),F';

for ('A'..'H') {
    print "$_: ", extract($_,$expr),"\n";
  }

exit;

A: ((B,G),A,(A,B))
B: (B,G)
C: (((B,G),A,(A,B)),C,(D,(E)))
D: (D,(E))
E: (E)
F: F
G: (B,G)
H:

论坛徽章:
0
16 [报告]
发表于 2016-08-05 17:52 |只看该作者
本帖最后由 jinzheng02279 于 2016-08-05 17:53 编辑
  1. #!/usr/bin/perl
  2. use strict;
  3. while (<DATA>){
  4.     if (/(\(\d+\*(.*)\))/){
  5.         print $1 . "\n";
  6.         print $2 . "\n";
  7.     }   
  8. }

  9. __DATA__
  10. 100-(5*(4+89-(34/5)))
复制代码
仅以这道题来说,这样匹配就足够了。

结果:
(5*(4+89-(34/5)))
(4+89-(34/5))

论坛徽章:
0
15 [报告]
发表于 2016-08-05 00:41 |只看该作者
104359176 发表于 2016-08-03 10:26
在语言中,这种嵌套的结构非常普遍,而这种嵌套是最简单的单结构。如果同时有几个结构嵌套在一起。

     ...


以前看编译原理,谈到按乔姆斯基的文法理论,印象模糊了,在网上找到下面这段文字:
在计算机领域中真正被使用的只有两者:三型文法和二型文法。前者的特征是语法中不存在递归下降结构,它的代表是基本正则表达式(扩展后的正则表达式情况略有不同);而二型文法即上下文无关文法,特征是任何语言元素在任何上下文中的含义始终保持一致。事实上,多数如今的程序设计语言语法都以此为基础。以上两者构成了如今所有实用计算机程序设计语言的分析器理论基础,也有成熟的数据结构和算法支持:三型文法的 NFA/DFA,以及二型文法的递归下降/LL(x)/LR(x)/LALR(x)。
而再向上的一型文法(上下文有关文法)和零型文法(任意图灵机可识别文法),计算机工程界则通常不会涉足。虽然有些时候,我们会开玩笑地将一些语法发展得极其复杂的语言称为上下文有关语言,比如 Perl;但事实上,这类语言仍然是通过二型文法进行分析,只是通过增补一部分规则来解决;至于真正可以解析上下文有关文法的线性有界自动机,则可以肯定地说,没有程序语言开发者会试图实现。
顺便说一句,一型文法事实上可以用来表述许多自然语言,拿来表述程序设计语言,多少有点杀鸡用牛刀的意思。

论坛徽章:
307
程序设计版块每周发帖之星
日期:2016-04-08 00:41:33操作系统版块每日发帖之星
日期:2015-09-02 06:20:00每日论坛发贴之星
日期:2015-09-02 06:20:00程序设计版块每日发帖之星
日期:2015-09-04 06:20:00每日论坛发贴之星
日期:2015-09-04 06:20:00每周论坛发贴之星
日期:2015-09-06 22:22:00程序设计版块每日发帖之星
日期:2015-09-09 06:20:00程序设计版块每日发帖之星
日期:2015-09-19 06:20:00程序设计版块每日发帖之星
日期:2015-09-20 06:20:00每日论坛发贴之星
日期:2015-09-20 06:20:00程序设计版块每日发帖之星
日期:2015-09-22 06:20:00程序设计版块每日发帖之星
日期:2015-09-24 06:20:00
14 [报告]
发表于 2016-08-04 21:47 |只看该作者
谢谢大神指点!

论坛徽章:
0
13 [报告]
发表于 2016-08-03 23:17 |只看该作者
sunzhiguolu 发表于 2016-08-02 22:56
回复 5# hztj2005

大神您能否提供一个示例代码, 关于您说的那个解决方案. 先谢谢大神了.


完全正则表达式可能就有困难,但程序实现好简单的,不用代码。
1、用一个正则表达式  m/(  \(   [^\(\)]  \)  )/ ,$1就捕捉到最里层的括号内容了。push 到一个数组。
2、再用一个正则表达式  s/\(   ([^\(\)])  \) /{ $1}/,把里层的括号替换掉。
继续循环就可以了,当然最后结果,需要把{}替换成()。不用大括号,用【】也可以。

















]

评分

参与人数 1信誉积分 +10 收起 理由
sunzhiguolu + 10 很给力!

查看全部评分

论坛徽章:
145
技术图书徽章
日期:2013-10-01 15:32:13戌狗
日期:2013-10-25 13:31:35金牛座
日期:2013-11-04 16:22:07子鼠
日期:2013-11-18 18:48:57白羊座
日期:2013-11-29 10:09:11狮子座
日期:2013-12-12 09:57:42白羊座
日期:2013-12-24 16:24:46辰龙
日期:2014-01-08 15:26:12技术图书徽章
日期:2014-01-17 13:24:40巳蛇
日期:2014-02-18 14:32:59未羊
日期:2014-02-20 14:12:13白羊座
日期:2014-02-26 12:06:59
12 [报告]
发表于 2016-08-03 10:45 |只看该作者
本帖最后由 jason680 于 2016-08-05 02:39 编辑

Dear All:  给回应者,楼主:

  说困难很困难,要解析结构文法(grammar)+ debug + ...
     对学过的文法架构解析也是很简单,写出正确文法描述,就能做出所要(四则运算)代码。
     S -> T + T | T - T | T
     T -> F * F | F / F | F
     F -> NUMBER | '(' S ')'
     NUMBER ->  0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9

  说简单很简单,只要求值(value) ---- eval function

$ echo "100- ( 5* (4+89- (34/5) ) )" | perl -lpe 'print eval'
-331
  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP