为什么在我的正则表达式模式中使用POSIX字符类会产生意想不到的结果?

时间:2010-02-25 09:44:13

标签: regex perl sorting

我遇到了一些奇怪的Perl行为:在regexp中使用Posix字符类完全改变了结果字符串的排序顺序。

这是我的测试程序:

sub namecmp($a,$b) {
  $a=~/([:alpha:]*)/;
  # $a=~/([a-z]*)/;
  $aword= $1;

  $b=~/([:alpha:]*)/;
  # $b=~/([a-z]*)/;
  $bword= $1;
  return $aword cmp $bword;
};

$_= <>;
@names= sort namecmp split;
print join(" ", @names), "\n";

如果使用[a-z]更改为已注释掉的正则表达式,则会获得正常的词典排序顺序。但是,Posix [:alpha:]字符类会产生一些怪异的排序顺序,如下所示:

$test_normal
aaa aab aac aba abb abc aca acb acc baa bab bac bba bbb bbc bca bcb bcc caa cbb
aaa aab aac aba abb abc aca acb acc baa bab bac bba bbb bbc bca bcb bcc caa cbb

$test_posix
aaa aab aac aba abb abc aca acb acc baa bab bac bba bbb bbc bca bcb bcc caa cbb
baa bab bac bba bbb bbc bca bcb bcc caa cbb aba abb abc aca acb acc aab aac aaa

我最好的猜测是,Posix角色类正在激活某些我从未听说过并且没有要求的语言环境。我想对“医生,医生,当我做这个时会有伤害的逻辑反应!”是的,“好吧,不要 ,然后!”。

但是,谁能告诉我这里发生了什么,为什么?我使用的是perl 5.10,但我相信它也适用于perl 5.8。

3 个答案:

答案 0 :(得分:13)

字符类[:alpha:]表示Perl正则表达式中的字母字符,但方括号 not 表示它们在正则表达式中通常执行的操作。所以你需要:

$a=~/([[:alpha:]]*)/;

perlre中提到了这一点:

  

POSIX字符类语法

[:class:]
     

也可用。请注意,[]括号是字面的;它们必须始终在字符类表达式中使用。

# this is correct:
$string =~ /[[:alpha:]]/;

# this is not, and will generate a warning:
$string =~ /[:alpha:]/;

答案 1 :(得分:8)

你所写的不是Perl的任何想象力。你可以逃脱它,因为你关掉了warnings。如果您使用了警告,perl会告诉您

POSIX syntax [: :] belongs inside character classes in regex; marked by <-- HERE in m/([:alpha:] <-- HERE *)/ at j.pl line 4.

POSIX syntax [: :] belongs inside character classes in regex; marked by <-- HERE in m/([:alpha:] <-- HERE *)/ at j.pl line 8.

想象一下!

现在,perl也会告诉你:

Illegal character in prototype for main::namecmp : $a,$b at j.pl line 3.

因为,Perl不是C. Perl没有您似乎尝试使用的那种函数原型。

这次在Perl中编写完全相同的功能的更好方法是:

use warnings; use strict;

sub namecmp {
    my ($aword) = $a =~ /([[:alpha:]]*)/;
    my ($bword) = $b =~ /([[:alpha:]]*)/;
    return $aword cmp $bword;
}

print join(' ', sort namecmp split ' ', scalar <>), "\n";

答案 2 :(得分:6)

因为Perl不支持此表单中的POSIX字符类。 (使用[[:alpha:]]。请参阅@Greg's answer

所以

[:alpha:]

被解释为由字符“a”,“h”,“l”,“p”和“{{1}组成的字符类}”。

现在,对于在开头没有包含: 的字符串(因为[ahlp:]),例如“*”匹配将返回一个空字符串。当然,空字符串当然比任何其他字符串小,所以它们将在开头排列。