大家帮忙看看这个程序怎么写的(已解决)

大家帮忙看看这个程序怎么写的(已解决)

#!/usr/bin/perl

use strict;
use warnings;

my $tmp='bf792596                                        119-118        107-270        bf792560        1';

while($tmp=~/([a-z]{1,2}[0-9]{4,6})/g){
        my $tmp2=$1;
        $tmp=~s/$tmp2/bf792560--/;
       
}
print $tmp;

这个程序中总是无法运行,不知道是什么原因,请大家帮忙看看,谢谢拉

不是不执行,是死循环了,你看看一个是$1取出来是什么,一个是替换模式是否有问题,手头还有点别的事,没来得及调试。
祝你成功:P
$1取出来bf792596
是循环的问题,把while换成if运行2次可以,但是我不知道怎么解决
while 改成 for
$1 改成 $_
土人问一下
直接替换不可以么?
你还是说一下你这个程序的目的吧

[Copy to clipboard] [ - ]
CODE:
#!/usr/bin/perl
use strict;
use warnings;
my $tmp='bf792596                                        119-118        107-270        bf792560        1';
$tmp =~ s/[a-z]{1,2}[0-9]{4,6}/bf92560--/g;
print "$tmp\n";

估计是我理解错误了


QUOTE:
原帖由 duziteng 于 2008-2-5 18:09 发表
#!/usr/bin/perl

use strict;
use warnings;

my $tmp='bf792596                                        119-118        107-270        bf792560        1';

while($tmp=~/([a-z]{1,2}[0-9]{4,6})/g){
        my $tmp2=$1;
        $tmp=~s/$tmp2/bf792560--/;
       
}
p ...

你错误的原因在于(mastering regex)

QUOTE:
Every string in Perl has associated with it a "current match location" at which the transmission first attempts the match. It's a property of the string, and not associated with any particular regular expression. When a string is created or modified, the "current match location" starts out at the beginning of the string

这段话的意思就是说正则引擎在进行匹配的时候是从一个string的pos处开始的(可以用pos来查看,具体见下面的例子),但是每次string改变的这个string的pos就会被reset到string的开头,也就是为0.
下面的代码可以看出您代码的问题所在

[Copy to clipboard] [ - ]
CODE:
#!/usr/bin/perl
use strict;
use warnings;
my $tmp='bf792596                                        119-118        107-270        bf792560        1';
print "$tmp\n";
while($tmp=~/(?{print "starting match at $`|$'\n"})([a-z]{1,2}[0-9]{4,6})/g){
    printf "The current positon is %d\n",pos($tmp);
    sleep 1;
    my $tmp2=$1;
    $tmp=~s/$tmp2/bf792560--/;
    printf "The current positon is %d\n",pos($tmp);
}
print $tmp . "\n";
[/color]
说明一下:
1.
[code]
while($tmp=~/(?{print "starting match at $`|$'\n"})([a-z]{1,2}[0-9]{4,6})/g)

这段代码就是除了匹配以外在每次匹配前打印出匹配的开始出(用|界定),具体看$`,$'什么意思
2.在一次匹配以后打印下string的pos值
然后再修改过$tmp以后再打印下string的pos值


运行结果如下:

QUOTE:
<lig@other-server:~/chinaunix>$ ./test
bf792596                                        119-118        107-270        bf792560        1
starting match at |bf792596                                        119-118        107-270        bf792560        1
The current positon is 8
Use of uninitialized value in printf at ./test line 11.
The current positon is 0
starting match at |bf792560--                                        119-118        107-270        bf792560        1
The current positon is 8
Use of uninitialized value in printf at ./test line 11.
The current positon is 0
starting match at |bf792560----                                        119-118        107-270        bf792560        1
The current positon is 8
Use of uninitialized value in printf at ./test line 11.
The current positon is 0
starting match at |bf792560------                                        119-118        107-270        bf792560        1
The current positon is 8
Use of uninitialized value in printf at ./test line 11.
The current positon is 0
starting match at |bf792560--------                                        119-118        107-270        bf792560        1
The current positon is 8
Use of uninitialized value in printf at ./test line 11.
The current positon is 0
starting match at |bf792560----------                                        119-118        107-270        bf792560        1
The current positon is 8

从这里可以看到
每次匹配都是从string的开头开始的,匹配后string的position设置为8,然后改变了$tmp以后,string的position又reset成0
这样就造成了死循环

如果你一定要用这样的方法
那么可以先把string的pos保留
然后赋值以后再恢复

[Copy to clipboard] [ - ]
CODE:
my $pos = pos($tmp);
    my $tmp2=$1;
    $tmp=~s/$tmp2/bf792560--/;
    pos($tmp) = $pos;

这样可以避免出现死循环
但是是有个小bug的(不能替换第二次出现的bf792560)
问题出在您用的替换上

[Copy to clipboard] [ - ]
CODE:
$tmp=~s/$tmp2/bf792560--/;

可以改成全局替换

[Copy to clipboard] [ - ]
CODE:
$tmp=~s/$tmp2/bf792560--/g;

最后完整的代码(加上一些debug信息)如下

[Copy to clipboard] [ - ]
CODE:
#!/usr/bin/perl
use strict;
use warnings;
my $tmp='bf792596   119-118    107-270   bf792560      1';
print "$tmp\n";
while($tmp=~/(?{print "starting match at $`|$'\n"})([a-z]{1,2}[0-9]{4,6})(?{print "matched at $`<$&>$'\n"})/g){
    printf "The current positon is %d\n",pos($tmp);
    my $pos = pos($tmp);
    my $tmp2=$1;
    $tmp=~s/$tmp2/bf792560--/g;
    pos($tmp) = $pos;
    printf "Restore positon is %d\n",pos($tmp);
}
print $tmp . "\n";

运行结果

QUOTE:
<lig@other-server:~/chinaunix>$ ./test
bf792596   119-118    107-270   bf792560      1
starting match at |bf792596   119-118    107-270   bf792560      1
matched at <bf792596>   119-118    107-270   bf792560      1
The current positon is 8
Restore positon is 8
starting match at bf792560--   119-118    107-270   |bf792560      1
matched at bf792560--   119-118    107-270   <bf792560>      1
The current positon is 42
Restore positon is 42
bf792560----   119-118    107-270   bf792560--      1

谢谢大家