URL: https://www.opennet.ru/cgi-bin/openforum/vsluhboard.cgi
Форум: vsluhforumID9
Нить номер: 8150
[ Назад ]

Исходное сообщение
"regexp  + UTF-8 = не работает"

Отправлено Аноним , 12-Мрт-09 19:45 
Добрый день, уважаемые.

Подскажите пожалуйста почему Perl не парсит рег.выражения на русском вида [а-яА-Я] при использовании UTF8. Хотя с CP1251 проблем нет(если делаю iconv + использую setlocale(LC_CTYPE,"ru_RU.CP1251");

Имею:
$ locale
LANG=ru_RU.UTF-8
LC_CTYPE="ru_RU.UTF-8"
LC_NUMERIC="ru_RU.UTF-8"
LC_TIME="ru_RU.UTF-8"
LC_COLLATE="ru_RU.UTF-8"
LC_MONETARY="ru_RU.UTF-8"
LC_MESSAGES="ru_RU.UTF-8"
LC_PAPER="ru_RU.UTF-8"
LC_NAME="ru_RU.UTF-8"
LC_ADDRESS="ru_RU.UTF-8"
LC_TELEPHONE="ru_RU.UTF-8"
LC_MEASUREMENT="ru_RU.UTF-8"
LC_IDENTIFICATION="ru_RU.UTF-8"
LC_ALL=

Файл, к-ый хочу пропарсить имеет строки вида:
"Администратор" "Марфа Васильевна"
Естественно он сохранен в UTF-8

Мой скрипт:
#!/usr/bin/perl

use strict;
use warnings;

open(DATA,'file.txt');
my $infile = <DATA>;
close DATA;

while($infile =~ m/([А-Яа-я]+)/gi) {
        print "$1\n";
}

На выходе получаю:
$ perl report.pl
Админи


а
о
Ма

а
Ва
ил
евна

В чем трабла?
На википедии написано что с юникодом проблем не должно быть:
"Для использования последовательностей букв необходимо установить правильную кодовую страницу в которой эти последовательности будут идти в порядке от и до указанных символов. Для русского языка это Windows-1251, ISO 8859-5 и Юникод, так как в DOS-855, DOS-866 и KOI8-R русские буквы не идут одной целой группой или не упорядочены по алфавиту."


Содержание

Сообщения в этом обсуждении
"regexp  + UTF-8 = не работает"
Отправлено angra , 12-Мрт-09 20:06 
man perluniintro
man perlunifaq
man perlunitut
man perlunicode
Можно начать с попытки добавлять
use utf8;
use open ':encoding(utf8)';
utf8::upgrade($infile);
Если не получится, то придется таки читать.

"regexp  + UTF-8 = не работает"
Отправлено Аноним но другой , 13-Мрт-09 01:52 
>man perluniintro
>man perlunifaq
>man perlunitut
>man perlunicode
>Можно начать с попытки добавлять
>use utf8;
>use open ':encoding(utf8)';
>utf8::upgrade($infile);
>Если не получится, то придется таки читать.

Добавил, теперь скрипт выглядит так:
$ less report.pl
#!/usr/bin/perl

use utf8;
use open ':encoding(utf8)';
utf8::upgrade($infile);

open(DATA,'file.txt');
my $infile = <DATA>;
close DATA;

while($infile =~ m/([А-Яа-я]+)/gi) {
        print "$1\n";
}

$ less file.txt
"Администратор" "Марфа Васильевна"

$ ./report.pl
Wide character in print at page.analyser_simplified.pl line 12.
Администратор
Wide character in print at page.analyser_simplified.pl line 12.
Марфа
Wide character in print at page.analyser_simplified.pl line 12.
Васильевна

Работает!! Спасибо. Осталось теперь тока разобраться с руганью про wide character.
завтра почитаю. спасибо.


"regexp  + UTF-8 = не работает"
Отправлено angra , 13-Мрт-09 02:14 
Ну не все же одновременно надо было добавлять. Кроме того utf8::upgrade($infile); перед использованием my $infile вообще не имеет смысла. Используйте use strict дабы избегать таких ошибок.
Попробуйте такой вариант:
#!/usr/bin/perl -w
use strict;

use utf8;

open(DATA,'file.txt');
my $infile = <DATA>;
utf8::decode($infile);
close DATA;

while($infile =~ m/([А-Яа-я]+)/gi) {
  my $s=$1;
  #нельзя напрямую применять encode к $1 иначе получим бред после первой строки
  utf8::encode($s);
  print "$s\n";
}

А вообще работа с юникодом в перле(да и в большинстве других языков) это шаманство, особенно когда много _различных_ потоков ввода/вывода.


"regexp  + UTF-8 = не работает"
Отправлено gaa , 12-Мрт-09 21:46 
>Мой скрипт:
>#!/usr/bin/perl

В какой кодировке файл скрипта сохранён?

И обычно во всех регекспах есть спецпоследовательность для обозначения любого набора букв. Что-то вроде [[:alnum:]] или \w, уж не знаю как в перле.


"regexp  + UTF-8 = не работает"
Отправлено angra , 13-Мрт-09 00:54 
>И обычно во всех регекспах есть спецпоследовательность для обозначения любого набора букв.
>Что-то вроде [[:alnum:]] или \w, уж не знаю как в перле.

Это по умолчанию только для английских, причем не только в перле. Кроме того в эти классы цифры тоже входят, а в \w еще и подчеркивание.
Перл позволяет работать с возможностями isalpha для локалей, в том числе и utf8, но для этого нужно явно указывать use locale.



"regexp  + UTF-8 = не работает"
Отправлено gaa , 13-Мрт-09 01:25 
>>И обычно во всех регекспах есть спецпоследовательность для обозначения любого набора букв.
>>Что-то вроде [[:alnum:]] или \w, уж не знаю как в перле.
>Это по умолчанию только для английских, причем не только в перле.

В тикле под \w и [[:alpha:]] буквы из русской локали тоже подходят. Так что надо читать ман по конкретному языку.


"regexp  + UTF-8 = не работает"
Отправлено oklas , 03-Дек-13 15:53 
В перле к строкам прикручены внутренние флаги, в частности есть флаг что строка во внутреннем формате, только с этим форматом нормально работают регулярные выражения и всякие там length и т.п.

Большинство проблем с кодировками можно решить придерживаясь например такой схемы работы:

use utf8; # предписывает что константы и регулярные выражения, имеющие не-ASCII символы,
должны трактоваться как уникодные и приводиться ко внутреннему формату

use Encode; # включаем модуль работы с кодировками.

$bytes = encode('utf-8', $string); # в байты, (из внутреннего формата)
$string = decode('utf-8', $bytes); # преобразовать во внутренний формат

! ВАЖНО, если perl собран и операционная система настроена так, что внутреннее представление переменных в utf-8 и print'ы и прочее выводят в utf-8, то это не значит что не надо пропускать через decode( 'utf-8', ... ), строки пришедшие откуда-то (из socket'а или fcgi, или модуля какого-нибудь и т.п.) то что строка в utf-8 еще не значит что она во внутреннем формате.

При работе с файлами можно использовать специальный синтаксис при открытии:

open FH, "<:utf8", $filename; # подробнее "perldoc -f open"


"regexp  + UTF-8 = не работает"
Отправлено Анатолий , 21-Авг-14 09:38 
>[оверквотинг удален]
> $bytes = encode('utf-8', $string); # в байты, (из внутреннего формата)
> $string = decode('utf-8', $bytes); # преобразовать во внутренний формат
> ! ВАЖНО, если perl собран и операционная система настроена так, что внутреннее
> представление переменных в utf-8 и print'ы и прочее выводят в utf-8,
> то это не значит что не надо пропускать через decode( 'utf-8',
> ... ), строки пришедшие откуда-то (из socket'а или fcgi, или модуля
> какого-нибудь и т.п.) то что строка в utf-8 еще не значит
> что она во внутреннем формате.
> При работе с файлами можно использовать специальный синтаксис при открытии:
> open FH, "<:utf8", $filename; # подробнее "perldoc -f open"

Мне странно читать подобные недовольсва... некоторые абсолютно уверены, что это какая-то ошибка и потому не рабоате! Нет граждане непонимающие это не ошибка... И оно не должно работать Просто потому что всё это работает через ctype функции... А  они не работают с мультибайтовыми кодировками! Ещё более странно даже не это, а то, что люди с таким упрорством пытаются использовать самую неудобную и самую тормознутую из всех кодировок utf8... Я не знаю ни одного приложения где такая кодировка действительно нужна. За исключением разве что языков с очень большим числом иероглифов как в китайском... Но мы же не китайцы!!!  В большинстве приложений хватает ASCII кодировок и это разумно использовать именно их! Но если вам не хватает симоволв или надо одновременно более 2-х языков сразу(в вебе к примеру...) то используйте вы Unicode. Это на порядок проще и быстрее!!! И там всё рабоатет. Функции другие, н отак всё тоже самое... Открою вам секрет, UTF8 это не ASCII кодировка и не Unicode.. Это мудьтибайтовая кодировка... И отсюда все беды! Никогда её не используйте и у вас не будет проблем. Перекодировать строку из utf8 в любую другую очень прсото с помощью стандартной функции iconv.


"regexp  + UTF-8 = не работает"
Отправлено oklas , 21-Авг-14 10:53 
- никаких проблем с использовнием utf8 в перл не возникает,
  и в частности в связи с тем что кодировка мультибайтовая.

- тормознутой кодировка быть не может, могут быть тормознутыми
  алгоритмы (работающие с данными в разных кодировках).

- на этапе обучения всегда бывают вопросы, здесь и есть их место.

- если есть данные о несоответствии поведения перл описанному
  в документации пишите разработчикам перл.

- "люди с таким упрорством пытаются использовать" - это вы видимо
  про разработчиков таких систем как google yandex rambler и т.д.


"regexp  + UTF-8 = не работает"
Отправлено Анатолий , 21-Авг-14 09:47 
А вы не пробовали задать другую локаль к примеру вызвав функцию setlocale? И у вас сразу всё станет настроено на другой язык и другую кодировку.. Так же легко перестроить среду с которой вы работаете, к примеру редактор, сообщения об ошибках и т.п.  Да хоть всю систему если надо... Если у вас нет соотвствующей локализации для perl а ид программ, то их легко скачать с интернета и установить!!! Это же свободное ПО и там есть все мыслимые и немыслимые локализации!!! Ну в крайнем случае можете написать свою... Но нафига, если есть готовая!