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

Я столкнулся с некоторым странным поведением Perl: использование класса символов 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 ]

13 голосов
/ 25 февраля 2010

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

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

Это упоминается в perlre :

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

[:class:]

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

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

# this is not, and will generate a warning:
$string =~ /[:alpha:]/;
8 голосов
/ 25 февраля 2010

То, что вы пишете, не является 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";
6 голосов
/ 25 февраля 2010

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

Итак

[:alpha:]

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...