如何匹配两个空行之间的行?(结帖)



QUOTE:
原帖由 mouse.rice 于 2008-2-26 14:52 发表

请教,在这里,这个@ARGV代表什么参数?关于@ARGV一直没有理解透彻。总感觉Perl语法很微妙!多谢了!

@ARGV就是命令行的参数
比如说你运行一个程序
./application a b c d
a b c d就是命令行参数
各个元素之间以空格分割
所以
@ARGV= qw (a b c d)
也就是说
$ARGV[0] 是a
$ARGV[1] 是b
$ARGV[2]是c
$ARGV[3]是d

顺便说一句
程序本身的名字存在
$0里面
$0在这里就是application

@ARGV就是一个特殊的数组,里面存放的是所有的待处理的命令行参数,常用的是<>


比如下面是一段很简单的代码

[Copy to clipboard] [ - ]
CODE:
#!/usr/bin/perl
while(<>){
print;
}

比如你传递给它的参数是a b c
哪这个程序就把a b c 的内容打印出来
<>是将@ARGV的内容一个一个shift的过程

可以用如下的代码看这个过程

[Copy to clipboard] [ - ]
CODE:
#!/usr/bin/perl
print "Original ARGV is @ARGV\n";
while(<>){
print "ARGV is @ARGV\n";
print;
}

运行结果

QUOTE:
<lig@other-server:~/chinaunix>$ ./read a b c
Original ARGV is a b c
ARGV is b c
file a
ARGV is c
file b
ARGV is
file c

也可以显示的写成

[Copy to clipboard] [ - ]
CODE:
#!/usr/bin/perl
while(@ARGV){
my $text = shift;
open my $file,"<","$text" or die "Fail to open $text $!";
while(<$file>){
  print;
  }
  }

@ARGV这个数组你可以自己随意操作
perl的话很多情况下都有默认值
像一开始的shift
默认就是对@ARGV进行操作
这也是perl比较难学的原因
但是一旦你习惯了这种思维,你就会发现这是个很人性化的语言
因为Larry Wall本身就是学习人类语言的


更多的对@ARGV进行操作的
可以参见
perldoc Getopt::Std
perldoc Getopt::Long


[Copy to clipboard] [ - ]
CODE:
#!/usr/bin/perl
use strict;
open(FILE,"mail.txt") || die "error: $!";
$_ = join '',<FILE>;
#print $_;
print $1 while /^\s*\n(^.+\n)(?=^\s*\n)/gm

这段正则谁能帮忙解释一下?
#!/usr/bin/perl
use warnings;
use strict;

open(F,"<urfile") or die "Can't open urfile: $!\n";
$/="";
while(<F>) {
        chomp;
        print "$_\n" if $. == 2;
}


[Copy to clipboard] [ - ]
CODE:
#!/usr/bin/perl
use strict;
open(FILE,"mail.txt") || die "error: $!";
$_ = join '',<FILE>;
#print $_;
print $1 while /^\s*\n(^.+\n)(?=^\s*\n)/gm

这个正则还是不太理解,这个程序就是匹配两个空行之间的行的程序,哪位还能指点指点?


[Copy to clipboard] [ - ]
CODE:
#!/usr/bin/perl
use strict;
open(FILE,"mail.txt") || die "error: $!";
$_ = join '',<FILE>;
#print $_;
print $1 while /^\s*\n(^.+\n)(?=^\s*\n)/gm

join那一行就是将所有的输入行以空白连接成一个字符串

正则的话注意以下几点
/m 是多行模式,所以^可以匹配内部的开头,^原本只能够用来匹配字符串的开头,但在/m模式中亦匹配\n后的位置
/g 是global模式,与此相关的一些操作是pos和\G \c
/^\s*\n(^.+\n)(?=^\s*\n)/gm的作用就是
1.匹配一个空行(^\s*\n),注意这里^的意思已经发生了改变,因为/m的作用
2.一个非空行(^.+\n), 注意"."不能匹配\n,除非由/s加以修饰
3.(?=^\s*\n) 是look ahead,它匹配的是一个位置,而非具体的内容(^,$匹配的亦是位置),表示紧接着的是一个空行

所以这个程序的作用只能用来匹配空行之间的内容只有一行的情况,很可能不是你需要的
可以看下面的演示

QUOTE:
<lig@other-server:~/chinaunix>$ cat mail
this
is

fjlsjflsf

fjlsjflsjlf
sjlfjsldfjlsjflk
<lig@other-server:~/chinaunix>$ ./blank
fjlsjflsf

因为空行之间只有一行非空,所以匹配

QUOTE:
<lig@other-server:~/chinaunix>$ cat mail
this
is

fjlsjflsf
fjlsjflsf

fjlsjflsjlf
sjlfjsldfjlsjflk
<lig@other-server:~/chinaunix>$ ./blank

有多行,所以不能匹配
不知道这是不是你真的想要的



QUOTE:
原帖由 ly5066113 于 2008-2-27 16:38 发表
#!/usr/bin/perl
use warnings;
use strict;

open(F,"

相当强悍
居然没有想到


QUOTE:
原帖由 churchmice 于 2008-3-19 18:56 发表

#!/usr/bin/perl
use strict;
open(FILE,"mail.txt") || die "error: $!";
$_ = join '',;
#print $_;
print $1 while /^\s*\n(^.+\n)(?=^\s*\n)/gm

join那一行就是将所有的输入行以空白连接成一个字 ...

“/g 是global模式,与此相关的一些操作是pos和\G \c”

请问pos和\G \c的具体用法是什么呢?


QUOTE:
原帖由 __lxmxn__ 于 2008-3-20 01:19 发表

“/g 是global模式,与此相关的一些操作是pos和\G \c”

请问pos和\G \c的具体用法是什么呢?

1.每个string都有一个pos和其关联,表示正则引擎开始进行匹配的位置,这个位置可以有pos返回或者由pos改写
见如下代码:

[Copy to clipboard] [ - ]
CODE:
#!/usr/bin/perl
use strict;
use warnings;
my $a = "this is a test";
my $b = "this is a test";
$, = " ";
$\ = "\n";
pos($a) = 4;
print "matched $`<$&>$'" if $a =~ /is/g;
print "matched $`<$&>$'" if $b =~ /is/g;

这一代码中$a $b完全一样,差别在于人为的将$a的pos设置成了4,也就是说从(this|is a test)开始匹配
运行结果

QUOTE:
<lig@other-server:~/chinaunix>$ ./pos
matched this <is> a test
matched th<is> is a test



[Copy to clipboard] [ - ]
CODE:
#!/usr/bin/perl
use strict;
use warnings;
my $a = "1a2a3a4a";
while($a =~ m/\d+/g){
    printf "matched $`<$&>at location %d\n",pos($a);
    }

这一代码可以看的更仔细,随着正则引擎从左到右的扫描,pos($a)的位置也不断的发生变化

QUOTE:
<lig@other-server:~/chinaunix>$ ./location
matched <1>at location 1
matched 1a<2>at location 3
matched 1a2a<3>at location 5
matched 1a2a3a<4>at location 7

这就是pos的作用
2.\G的作用
可以结合pos来解释
\G表示上一次匹配完之后的位置,可以理解为\G就是string的pos值
关于这个可以引用effective perl programming的一个例子

QUOTE:
s/\G0/ /g
Once upon a time in 1996, someone asked comp.lang.perl.misc if there was a way to replace leading zeros in a string with spaces. This was Randal's response.

This substitution uses the \G anchor, which works with the /g pattern match flag. The \G anchor refers to either the beginning of the string or the end of the previous /g match for that pattern. When the pattern match starts up, /\G0/ matches a 0 at the start of the string. If the match is successful, /\G0/ will match another 0 if it immediately follows the first one. The pattern will continue matching until it encounters a character that isn't a 0. While this is going on, the 0s are being replaced with spaces.

这里需要注意一点,pos一定要配合/g使用才有意义,虽然匹配的内容和没有/g修饰是一样的
如果单纯的用 m//;
则不管匹配是否成功,pos都会被reset成undef

[Copy to clipboard] [ - ]
CODE:
#!/usr/bin/perl
use strict;
use warnings;
my $a = "this is a test";
$, = " ";
$\ = "\n";
$a =~ /^this/g;
print "now position of \$a is ",pos($a),"\n";
print "1: matched at &`<$&>$'" if $a =~ /\Gis/;
print "2: matched at &`<$&>$'" if $a =~ /\G is/;



QUOTE:
<lig@other-server:~/chinaunix>$ ./pos
now position of $a is  4

2: matched at &`< is> a test