Почему использование класса символов POSIX в моем шаблоне регулярных выражений дает неожиданные результаты?

я столкнулся с некоторым странным поведением Perl: использование класса символов Posix в регулярном выражении полностью изменяет порядок сортировки для результирующих строк.

вот моя тестовая программа:

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

  $b=~/([:alpha:]*)/;
  # $b=~/([a-z]*)/;
  $bword= ;
  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 ответов


класс персонажа [:alpha:] представляет Альфа-символы в регулярных выражениях Perl, но квадратные скобки делают не означает, что они обычно делают в регулярных выражениях. Нужно так:

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

об этом говорится в perlre:

синтаксис класса символов POSIX

[:class:]

также доступна. Обратите внимание, что [ и ] скобки являются буквальными; они всегда должны использоваться внутри символа выражение класса.

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

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

то, что вы пишете, не является 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";

потому что Perl не поддерживает классы символов POSIX в этой форме. (Используйте [[:alpha:]]. См.@Грега)

так

[:alpha:]

интерпретируется как класс символов, состоящий из символов"a","h","l","p" и ":".

теперь, для строк, которые не содержат [ahlp:] в начале (поскольку *), например,"baa" матч вернет пустую строку. Пустая строка, конечно, меньше, чем любые другие строки, поэтому они будут расположены в начале.