FAQ
Оргинал лежит на http://faq.perl.org/
Programming Tools
1. Интерактивный дебаг
2. Определить срисок модулей , установленных на системе
3. Дебаг программ
4. Профайлинг
5. Среда
6. Интеграция curses
7. Как ускорить работу перла ?
8. Как уменьшить затраты на память ?
9. Можно ли возвращать из функции ссылку на локальную переменную ?
10. Как увеличить скорость загрузки CGI-скриптов ?
11. Как закрыть исходники ?
12. Как откомпилировать перловый код в байт-код
13. Литература по OOP Perl
14. Линковка Си и Perl
15. Как получить полный список ошибок в Перл
16. Что такое MakeMaker
Data Manipulation
1. Как задать точность до знака после запятой в типе float ?
2. Конвертация данных в 8- и 16-ричном формате
3. Округление чисел
4. Как оперировать с матрицами
5. Как передать массив в функцию и вернуть результат в этот же массив
6. Как получить случайные числа в диапазоне 10-15
7. Работа с датами
8. Как проверять валидность данных
9. Как удалить/заменить/посчитать повторяющиеся символы
10. Как работает substr
11. Как подсчитать число вхождений подстроки в строку ?
12. Как работает функция split ?
13. Как удалить повторы из массива ?
14. Как определить - есть ли в данном массиве данный элемент ?
15. Как вычислить разницу или пересечение между двумя массивами ?
16. Как проверить на эквивалентность 2 массива ?
17. Как проверить - есть ли данный элемент в массиве ?
18. Нужны ли связные списки в перле ?
19. Как отсортировать массив ?
20. Пусть имеется массив . Как составить все-возможные комбинации из его элементов ?
21. Как оперировать операциями на битами ?
22. Как работать с хешем ?
23. Можно ли в хеш добавлять-удалять ключ в момент итерации над этим хешем ?
24. Как отыскать хеш по значению ?
25. Как узнать число элементов хеша ?
26. В чем разница между функциями delete и undef для хеша ?
27. Как получить уникальные ключи из 2-х хешей ?
28. Как в перле создать структуру , аналогичную си-шной по синтаксису ?
29. Как определить тип скаляра ?
30. Как сохранить данные между вызовами скрипта ?
31. Как можно использовать класс UNIVERSAL ?
Files
1. Как изменить , удалить или добавить строку в файл ?
2. Как подсчитать число строк в файле ?
3. Как скопировать файл ?
4. Как обращаться с хенлами файлов на процедурном уровне в качестве параметров ?
5. Можно ли использовать файловый хендл косвенно ?
6. Как открыть файл на чтение-запись ?
7. Как переименовать файл ?
8. Как открыть текстовой файл , прочитать оттуда число , сделать инкремент
9. Как изменить бинарный файл ?
10.Как получить время изменения файла ?
Regular Expressions
1. В каком стиле лучше писать регеспы ?
2. Как сделать , чтобы работала русская локаль для \w match ?
3. Как квотировать переменную внутри регеспа ?
4. Можно ли отдебажить регулярное выражение ?
5. Как вырезать из файла комменты в стиле си ?
6. Как правильно использовать т.н. квантификаторы - quantifiers (?, *, +, {}) ?
7. Как работает \b ?
8: Где можно применять \G ?
General Perl Language Issues
1. Каковы основные спецификаторы типов :
2. Как проигнорировать возвращаемые значения ?
3. Можно ли блокировать варнинги ?
4. Что такое extension ?
5. Как создать структуру ?
6. Как передать - и - вернуть из функции такие обьекты , как :
7. Как создать статическую переменную ?
8. Какая разница между local и my ?
9. Как использовать switch ?
10.Как определить имя текущего модуля ?
11.Как сделать большой блок комментариев ?
12.Как удалить пакет в рантайме ?
System Interaction
1. Как узнать название операционной системы ?
2. Как раскрасить вывод ?
3. Как контролировать ввод с клавы ?
4. Как очистить экран ?
5. Как пользователю ввести пароль ?
6. Как работать с портами ?
7. Как запустить другой процесс 7
8. Как сделать паузу меньше секунды ?
9. Как обработать исключение ?
10. Как захватить STDOUT, STDERR из внешней команды ?
11. Как запустить команду без помощи шелла ?
12. Можно ли использовать перл для telnet или ftp session ?
13. Как открыть файл без его блокировки ?
14. Как проинсталлировать модуль CPAN ?
15. Какая разница между require и use ?
16. Как добавить новый каталог в список module/library ?
Programming Tools
1. В: Как запустить интерактивный дебаг ?
О: Запустить из командной строки с ключом
perl -de 42
Можно проверить стек , переменные , установить точки прерывания
2. В: Как определить список модулей , установленных на системе ?
О: Для вывода всех установленных модулей :
use ExtUtils::Installed;
my $inst = ExtUtils::Installed->new();
my @modules = $inst->modules();
Для вывода имен файлов модулей :
use File::Find::Rule;
my @files = File::Find::Rule->file()->name( '*.pm' )->in( @INC );
Можно проверить наличие модуля по документации для него - если она есть :
prompt% perldoc Module::Name
Можно проверить наличие модуля из командной строки :
perl -MModule::Name -e1
3. В: Как выполнить дебаг программ ?
О: Использовать
use strict;
use warnings;
Использовать :
print
Использовать модуль Data::Dumper
use Data::Dumper qw( Dumper );
print STDERR "The hash is " . Dumper( \%hash ) . "\n";
4. В: Профайлинг
О: Использовать модуль Benchmark
use Benchmark;
timethese($count, { ... } )
На это будет выведен отчет
5. В: Среда
О: Еклипс , комодо , vi , emacs
6. В: Интеграция curses
О: На cpan имеется модуль для интеграции с перлом
7. В: Как ускорить работу перла ?
О: 1. Оптимизация программных алгоритмов
2. Использование модулей AutoSplit , AutoLoader
3. Интеграция с кодом на Си (например , cpan-ский модуль PDL написан на си)
4. Линковка к статическим библиотекам вместо расшаренных :
вместо libc.so -> libc.a
8. В: Как уменьшить затраты на память ?
О: 1. Использовать си-шные типы вместо аналогичных перловых , например массивы
2. Использовать битовые массивы вместо булевских
3. Использование системного malloc <-> встроенного перлового malloc
4. Читать большие файлы не целиком , а построчно
5. Не квотировать большие строки , т.е
вместо my $copy = "$large_string";
нужно my $copy = $large_string;
т.к. в первом случае будет 2 копии , а во втором одна
6. Передавать массивы и хеши по ссылке , а не по значению
7. Большие порции данных сбрасывать на диск
9. В: Можно ли возвращать из функции ссылку на локальную переменную ?
О: Можно - перловый GC ведет себя корректно :
sub makeone
{
my @a = ( 1 .. 10 );
return \@a;
}
for ( 1 .. 10 )
{
push @many, makeone();
}
10. В: Как увеличить скорость загрузки CGI-скриптов ?
О: Использовать модули mod_perl или mod_fastcgi
В первом случае скрипт компилится и при каждом последующем выполнении не форкается.
При этом mod_perl предоставляет перловым скриптам доступ к apache API
Во втором случае каждый скрипт превращается в самостоятельного демона
11. В: Как закрыть исходники ?
О: 1. Не давать прав на чтение при доступе из инета
2. Можно зашифровать исходники с помощью Filter::Simple и Filter::Util::Call
3. Можно откомпилировать байт-код
12. В: Как откомпилировать перловый код в байт-код
О: 1. Использовать Perl Archive Toolkit - аналог жабовского JAR
2. Использовать Perl Dev Kit - от ActivePerl
3. Perl2Exe
13. В: Литература по OOP Perl
О: 1. Object-Oriented Perl - Damian Conway
2. Intermediate Perl - Randal Schwartz
3. perldoc : perltoot, perlobj, perlboot, perltooc, and perlbot
14. В: Линковка Си и Perl
О: 1. perldoc : perlxstut, perlxs, xsubpp, perlguts - вызов Си из Перл
2. perldoc : perlembed, perlcall, perlguts - вызов Перл из Си
3. Использовать модуль Inline::C - интеграция си-шного кода напрямую в перловый
15. В: Как получить полный список ошибок в Перл
О: perldoc perldiag
В программе можно прописать use diagnostics;
16. В: Что такое MakeMaker
О: Модуль ExtUtils::MakeMaker генерит из Makefile из Makefile.PL .
Makefile уже используется для инсталяции перловых пакетов.
Data Manipulation
1. В: Как задать точность до знака после запятой в типе float ?
О: perldoc perlnumber
Использовать функции printf или sprintf :
printf "%.2f", 10/3;
my $number = sprintf "%.2f", 10/3;
2. В: Конвертация данных в 8- и 16-ричном формате
О: Использовать функции oct() и hex() для конвертации в десятичный формат .
$dec = hex("DEADBEEF");
$dec = oct("33653337357");
$decimal = oct( "0b$input" ); это 2-ное в 10-ное
Наоборот - 10-е в 16-ричное :
$hex = sprintf("%x", 3735928559); # lower case a-f
Наоборот - 10-е в 8-ричное :
$oct = sprintf("%o", 3735928559);
Наоборот - 10-е в 2-ричное :
$bin = sprintf("%b", 3735928559);
Восьмеричное число начинается с символа ноль , 16-ричное - с 0x.
3. В: Округление чисел
О: 1. Использовать printf
printf("%.3f", 3.1415926535); # prints 3.142
2. Модуль POSIX включает функции ceil(), floor()
use POSIX;
$ceil = ceil(3.5); # 4
$floor = floor(3.5); # 3
4. В: Как оперировать с матрицами
О: Использовать модули Math::Matrix , Math::MatrixReal
5. Как передать массив в функцию и вернуть результат в этот же массив
О: Использовать функцию map
@results = map { my_func($_) } @array;
@results = map { some_func($_) } (5 .. 25);
6. Как получить случайные числа в диапазоне 10-15
О: my $number = 10 + int rand( 15-10+1 );
7. В: Работа с датами
О: Использовать модуль POSIX
Для работы с форматированными датами использовать модули Date::Manip, Date::Calc, DateTime
День и неделя в году
$day_of_year = (localtime)[7];
my $day_of_year = strftime "%j", localtime;
my $week_of_year = strftime "%W", localtime;
Век :
return int((((localtime(shift || time))[5] + 1999))/100);
Вычислить вчерашнюю дату :
use DateTime;
my $yesterday = DateTime->now->subtract( days => 1 );
Или так :
use Date::Calc qw( Today_and_Now Add_Delta_DHMS );
my @date_time = Add_Delta_DHMS( Today_and_Now(), -1, 0, 0, 0 );
print "@date_time\n";
8. В: Как проверять валидность данных
О: Смотрите модули , в которых присутствует "Assert" и "Validate".
А также модули Regexp::Common, Business::ISBN, Business::CreditCard,
Email::Valid, Data::Validate::IP и т.д.
9. В: Как удалить/заменить/посчитать повторяющиеся символы
О: Удаление :
1. s/(.)\1/$1/g;
2. my $str = 'Russia';
$str =~ tr///cs;
Замена : в общем случае нужно применять модификатор /g в цикле :
Посчитать число повторов одного символа - в общем случае использовать модификатор tr/// :
tr/a// или tr/b//
Для повторяющейся группы символов надо использовать цикл.
10. В: Как работает substr
О: 1. $string = "Just another Perl Hacker";
$first_char = substr( $string, 0, 1 ); # 'J'
2. substr( $string, 13, 4, "Perl 5.8.0" );
3. substr( $string, 13, 4 ) = "Perl 5.8.0";
11. В: Как подсчитать число вхождений подстроки в строку ?
О: Если нужно подсчитать число вхождений символа , нужно использовать модификатор tr///
$string = "ThisXlineXhasXsomeXx'sXinXit";
$count = ($string =~ tr/X//);
print "There are $count X characters in the string";
Для нахождения подстроки прийдется использовать цикл - пример - подсчитать число отрицательных чисел :
$string = "-9 55 48 -2 23 -76 4 14 -44";
while ($string =~ /-\d+/g) { $count++ }
print "There are $count negative numbers in the string";
12. В: Как работает функция split ?
О: Можно сделать собственную реализацию split :
$text = "1,2,3,4,5,6,7,8,9";
@new = ();
push(@new, $+) while $text =~ m{([^,]+),?}gx;
push(@new, undef) if substr($text,-1,1) eq ',';
Получим массив 1 2 3 4 5 6 7 8 9
Стандартный вариант решения :
use Text::ParseWords;
@new = quotewords(",", 0, $text);
Еще - получить массив из строки с разделителем пробел :
my $line = ' fred barney betty ';
my @columns = split /\s+/, $line;
Еще - получить массив из строки с разделителем || :
my $line = 'fred||barney||betty';
my @columns = split /\|/, $line;
13. В: Как удалить повторы из массива ?
О: Использовать хеш :
@array=(1,2,3,4,1,1,1,2,2,2,2,3,4,5,6,6,6,5,4,3,3,3,3);
my %hash = map { $_, 1 } @array;
my @result_array = keys %hash;
foreach $un (@result_array)
{
print "$un\n";
}
Второй вариант - использовать стандартный grep :
my @unique = grep { ! $seen{ $_ }++ } @array;
14. В: Как определить - есть ли в данном массиве данный элемент ?
О: Составить промежуточный массив индексов :
@primes = (2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31);
@is_tiny_prime = ();
for (@primes) { $is_tiny_prime[$_] = 1 }
или так :
@istiny_prime[@primes] = (1) x @primes;
Стандартный подход - для нахождения отдельного элемента :
my $is_there = grep $_ eq 17, @primes;
15. Как вычислить разницу или пересечение между двумя массивами ?
О: Использовать все тот же хеш :
@array1 = (1,2,3,4,5,6,7,8,9,10);
@array2 = (9,10,11,12,13,14,15,16);
@union = @intersection = @difference = ();
%count = ();
foreach $element (@array1, @array2) { $count{$element}++ }
foreach $element (keys %count)
{
push @union, $element;
push @{ $count{$element} > 1 ? \@intersection : \@difference }, $element;
}
16. В: Как проверить на эквивалентность 2 массива ?
О: $are_equal = compare_arrays(\@array1, \@array2);
sub compare_arrays
{
my ($first, $second) = @_;
no warnings; # silence spurious -w undef complaints
return 0 unless @$first == @$second;
for (my $i = 0; $i < @$first; $i++) {
return 0 if $first->[$i] ne $second->[$i];
}
return 1;
}
17. В: Как проверить - есть ли данный элемент в массиве ?
О: Стандартный подход :
use List::Util qw(first);
@array = ("Perl","Python","c++");
my $element = first { /Perl/ } @array;
Если нужно найти индекс искомого элемента в массиве
my( $found, $index ) = ( undef, -1 );
for( $i = 0; $i < @array; $i++ )
{
if( $array[$i] =~ /Perl/ )
{
$found = $array[$i];
$index = $i;
last;
}
}
18. В: Нужны ли связные списки в перле ?
О: В общем случае - нет. С помощью операций push , pop , shift ,unshift
всегда можно добавить/удалить произвольный элемент массива.
19. В: Как отсортировать массив ?
О: Стандартным способом - при этом генерится новый массив :
use List::Util 'shuffle';
@shuffled = shuffle(@list);
Другой вариант :
@idx = (1,2,3,4,5,6,5,4,3) ;
@idx = sort { $a <=> $b } @idx;
20. В: Пусть имеется массив . Как составить все-возможные комбинации из его элементов ?
О: @idx = (1,2,3,4,5) ;
sub permute (&@)
{
my $code = shift;
while ( $code->(@_[@idx]) )
{
my $p = $#idx;
--$p while $idx[$p-1] > $idx[$p];
my $q = $p or return;
push @idx, reverse splice @idx, $p;
++$q while $idx[$p-1] > $idx[$q];
@idx[$p-1,$q]=@idx[$q,$p-1];
}
}
permute {print"@idx\n"} split;
21. В: Как оперировать операциями над битами ?
О: Использовать pack() , unpack(), vec() плюс битовые операции :
$vector = "\xff\x0f\xef\xfe";
print "Ilya's string \\xff\\x0f\\xef\\xfe represents the number ",
unpack("N", $vector), "\n";
$is_set = vec($vector, 23, 1);
print "Its 23rd bit is ", $is_set ? "set" : "clear", ".\n";
pvec($vector);
set_vec(1,1,1);
set_vec(3,1,1);
set_vec(23,1,1);
set_vec(3,1,3);
set_vec(0,32,17);
set_vec(1,32,17);
sub set_vec {
my ($offset, $width, $value) = @_;
my $vector = '';
vec($vector, $offset, $width) = $value;
print "offset=$offset width=$width value=$value\n";
pvec($vector);
}
sub pvec {
my $vector = shift;
my $bits = unpack("b*", $vector);
my $i = 0;
my $BASE = 8;
print "vector length in bytes: ", length($vector), "\n";
@bytes = unpack("A8" x length($vector), $bits);
print "bits are: @bytes\n\n";
}
22. В: Как работать с хешем ?
О: Вначале нужно получить ключи с помощью функции keys.
Распечатка значений хеша :
foreach my $key ( keys %hash )
{
my $value = $hash{$key};
print "$value\n";
}
Можно отсортировать ключ :
foreach my $key ( sort keys %hash )
{
my $value = $hash{$key};
print "$value\n";
}
Если хеш очень большой и не хочется в памяти создавать список ключей ,
можно использовать функцию each() :
while( my( $key, $value ) = each( %hash ) )
{
print "$value\n";
}
23. В: Можно ли в хеш добавлять-удалять ключ в момент итерации над этим хешем ?
О: Нельзя.
24. В: Как отыскать хеш по значению ?
О: Чтобы найти индекс по значению , надо сделать реверс :
%by_value = reverse %hash;
$key = $by_value{$value};
Можно распечатать и ключ , и значение в цикле , не используя дополнительных затрат памяти :
while (($key, $value) = each %hash)
{
$by_value{$value} = $key;
print "$by_value{$value}\n";
print "$value\n";
}
25. В: Как узнать число элементов хеша ?
О: Просто использовать keys() :
$num_keys = keys %hash;
26. В: В чем разница между функциями delete и undef для хеша ?
О: Первая удаляет из хеша пару ключ-значение , вторая присваивает значению = undef
27. В: Как получить уникальные ключи из 2-х хешей ?
О: Более простой , но и более затратный по памяти способ :
@uniq = keys %{{%hash,%hash2}};
Менее затратный по памяти способ :
%seen = ();
while (defined ($key = each %hash)) {
$seen{$key}++;
}
while (defined ($key = each %hash2)) {
$seen{$key}++;
}
@uniq = keys %seen;
28. Как в перле создать структуру , аналогичную си-шной по синтаксису ?
О: Используя хеш :
$record = {
NAME => "Jason",
EMPNO => 132,
TITLE => "deputy peon",
AGE => 23,
SALARY => 37000,
PALS => [ "Norbert", "Rhys", "Phineas"],
};
29. В: Как определить тип скаляра ?
О: $str = "123a";
if ($str =~ /\D/) { print "has nondigits\n" }
if ($str =~ /^\d+$/) { print "is a whole number\n" }
if ($str =~ /^-?\d+$/) { print "is an integer\n" }
if ($str =~ /^[+-]?\d+$/) { print "is a +/- integer\n" }
if ($str =~ /^-?\d+\.?\d*$/) { print "is a real number\n" }
if ($str =~ /^-?(?:\d+(?:\.\d*)?|\.\d+)$/) { print "is a decimal number\n" }
if ($str =~ /^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/) { print "a C float\n" }
30. В: Как сохранить данные между вызовами скрипта ?
О: Использовать модуль Storable - при этом происходит кеширование данных на диск в файл:
use Storable;
store(\@array, "filename"); # сохранили в файл
@array3 = @{ retrieve("filename") }; # извлекли из файла
31. В: Как можно использовать класс UNIVERSAL ?
О: Его можно использовать для определения того , унаследован ли какой-то обьект
от какого-то типа , с помощью метода isa , напр :
use UNIVERSAL "isa";
$ref = [1, 2, 3];
if (isa($ref, 'ARRAY')) {
print "OK\n";
} else {
print "Not OK\n";
}
Метод can класса UNIVERSAL позволяет осуществлять проверку того,
имеет ли класс или объект метод с указанным именем (имя метода задано в виде текстовой строки).
Если такого метода нет, возвращается значение ложь.
Если метод найден, возвращается ссылка на метод. Пример:
$datacall = $object->can('getdata');
if ($datacall) ...
Files
1. В: Как изменить , удалить или добавить строку в файл ?
О: В примере читается текстовой файл и создается его клон :
open my $in, '<', "filename" or die "Can't read old file: $!";
open my $out, '>', "filename.new" or die "Can't write new file: $!";
while( <$in> )
{
print $out $_;
}
close $in;
close $out;
То же самое , но в клон будет добавлена новая строка в начале файла :
open my $in, '<', "filename" or die "Can't read old file: $!";
open my $out, '>', "filename.new" or die "Can't write new file: $!";
print $out "# Add this line to the top\n"; # <--- HERE'S THE MAGIC
while( <$in> )
{
print $out $_;
}
close $in;
close $out;
То же самое , но в исходном файле проверяются строки на наличие подстроки "Perl" ,
и в клоне она будет заменена на "perl"
open my $in, '<', "filename" or die "Can't read old file: $!";
open my $out, '>', "filename.new" or die "Can't write new file: $!";
print $out "# Add this line to the top\n";
while( <$in> )
{
s/\b(Perl)\b/perl/g;
print $out $_;
}
close $in;
close $out;
Следующий код заменяет произвольную - 5-ю по счету - строку в клон-файле :
open my $in, '<', "filename2" or die "Can't read old file: $!";
open my $out, '>', "filename2.new" or die "Can't write new file: $!";
while( <$in> ) # print the lines before the change
{
print $out $_;
last if $. == 4; # line number before change
}
my $line = <$in>;
print $out "555555555555\n";
while( <$in> ) # print the rest of the lines
{
print $out $_;
}
close $in;
close $out;
Следующий код пропустит при клонировании каждую 5-ю строку :
open my $in, '<', "filename3" or die "Can't read old file: $!";
open my $out, '>', "filename3.new" or die "Can't write new file: $!";
while( <$in> )
{
next unless $. % 5;
print $out $_;
}
close $in;
close $out;
Следующая команда перезаписывает inFile.txt , меняя при этом Fred на Barney
perl -pi -e 's/Fred/Barney/' inFile.txt
Back-up для файла inFile.txt :
perl -pi.bak -e 's/Fred/Barney/' inFile.txt
Вставка строки в определенное место :
perl -pi -e 'print "Put before third line\n" if $. == 3' inFile.txt
Вставить строку в начало файла :
perl -pi -e 'print "Put before first line\n" if $. == 1' inFile.txt
Вставить строку в определенную позицию :
perl -ni -e 'print; print "Put after fifth line\n" if $. == 5' inFile.txt
Для удаления строк :
perl -ni -e 'print unless /d/' inFile.txt
В следующем примере используется опция -i.
В текущем каталоге будут модифицированы все файлы с расширением .new
путем добавления в начало файла новой строки ,
при этом старый файл будет сохранен с расширением .orig
local($^I, @ARGV) = ('.orig', glob("*.new"));
while (<>) {
if ($. == 1) {
print "This line should appear at the top of each file\n";
}
s/\b(p)earl\b/${1}erl/i; # Correct typos, preserving case
print;
close ARGV if eof; # Reset $.
}
2. В: Как подсчитать число строк в файле ?
О: $lines = 0;
open(FILE, "filename") or die "Can't open `$filename': $!";
while (sysread FILE, $buffer, 4096) {
$lines += ($buffer =~ tr/\n//);
}
close FILE;
3. В: Как скопировать файл ?
О: use File::Copy;
copy( "filename1", "filename2" ) or die "Copy failed: $!";
4. В: Как обращаться с хенлами файлов на процедурном уровне в качестве параметров ?
О: Ссылку на файл можно передавать как на любой другой скаляр :
open my $fh, $file_name;
open local $fh, $file_name;
print $fh "Hello World!\n";
process_file( $fh );
Их можно размещать в массив и оперировать с ним :
my @fhs = ( $fh1, $fh2, $fh3 );
for( $i = 0; $i <= $#fhs; $i++ )
{
print {$fhs[$i]} "just another Perl answer, \n";
}
5. В: Можно ли использовать файловый хендл косвенно ?
О: Можно :
$fh = SOME_FH; # bareword is strict-subs hostile
$fh = "SOME_FH"; # strict-refs hostile; same package only
$fh = *SOME_FH; # typeglob
$fh = \*SOME_FH; # ref to typeglob (bless-able)
$fh = *SOME_FH{IO}; # blessed IO::Handle from *SOME_FH typeglob
Можно использовать IO::Handle для создания скаляра :
use IO::Handle;
$fh = IO::Handle->new();
Косвенный файл-хендл - это скаляр.
Для передачи файл-хендла в функцию :
sub accept_fh
{
my $fh = shift;
print $fh "Sending to indirect filehandle\n";
}
Примеры неправильного использования скаляра :
@fd = (*STDIN, *STDOUT, *STDERR);
print $fd[1] "Type it: "; # WRONG
$got = <$fd[0]> # WRONG
print $fd[2] "What was that: $got"; # WRONG
Примеры правильного использования скаляра :
print { $fd[1] } "funny stuff\n";
printf { $fd[1] } "Pity the poor %x.\n", 3_735_928_559;
6. В: Как открыть файл на чтение-запись ?
О: На чтение :
use Fcntl;
open(FH, "< $path") || die $!;
sysopen(FH, $path, O_RDONLY)
На запись :
open(FH, "> $path") || die $!;
sysopen(FH, $path, O_WRONLY|O_TRUNC|O_CREAT) || die $!;
sysopen(FH, $path, O_WRONLY|O_TRUNC|O_CREAT, 0666) || die $!;
Открыть файл для добавления в конец :
open(FH, ">> $path") || die $!;
sysopen(FH, $path, O_WRONLY|O_APPEND|O_CREAT) || die $!;
sysopen(FH, $path, O_WRONLY|O_APPEND|O_CREAT, 0666) || die $!;
Открыть файл для апдэйта - если он существует :
open(FH, "+< $path") || die $!;
sysopen(FH, $path, O_RDWR) || die $!;
Открыть файл для апдэйта - если он не существует :
sysopen(FH, $path, O_RDWR|O_CREAT) || die $!;
sysopen(FH, $path, O_RDWR|O_CREAT, 0666) || die $!;
7. В: Как переименовать файл ?
О: rename($old, $new) or system("mv", $old, $new);
8. В: Как открыть текстовой файл , прочитать оттуда число , сделать инкремент
и записать результат в файл ?
О: sysopen(FH, "filename", O_RDWR|O_CREAT) or die "can't open numfile: $!";
flock(FH, LOCK_EX) or die "can't flock numfile: $!";
$num = || 0;
seek(FH, 0, 0) or die "can't rewind numfile: $!";
truncate(FH, 0) or die "can't truncate numfile: $!";
(print FH $num+1, "\n") or die "can't write numfile: $!";
close FH
9. В: Как изменить бинарный файл ?
О: Можно просто :
perl -i -pe 's{window manager}{window mangler}g' /usr/bin/emacs
Если размер бинарника фиксирован :
$RECSIZE = 220; # size of record, in bytes
$recno = 37; # which record to update
open(FH, "+< somewhere") || die "can't update somewhere: $!";
seek(FH, $recno * $RECSIZE, 0);
read(FH, $record, $RECSIZE) == $RECSIZE || die "can't read record $recno: $!";
# munge the record
seek(FH, -$RECSIZE, 1);
print FH $record;
close FH;
10. В: Как получить время изменения файла ?
О: $write_secs = (stat($file))[9];
printf "file %s updated at %s\n", $file,
scalar localtime($write_secs);
Или так :
use File::stat;
use Time::localtime;
$date_string = ctime(stat($file)->mtime);
print "file $file updated at $date_string\n";
Regular Expressions
1. В: В каком стиле лучше писать регеспы ?
О: Рассмотрим пример :
s{<(?:[^>'"]*|".*?"|'.*?')+>}{}gs;
С помощью модификатора /x его можно привести к виду :
s{ < # открытие угловых скобок
(?: # Non-backreffing grouping paren
[^>'"] * # 0 or more things that are neither > nor ' nor "
| # or else
".*?" # a section between double quotes (stingy match)
| # or else
'.*?' # a section between single quotes (stingy match)
) + # all occurring one or more times
> # closing angle bracket
}{}gsx; # replace with nothing, i.e. delete
В качестве разделителя как правило используется символ /.
Иногда удобно применить другую комбинацию :
s/\/usr\/local/\/usr\/share/g; # не очень понятно
s#/usr/local#/usr/share#g; # лучше
Если вывод не влезает на одну строку , можно применить модификатор /m ,
который поддерживает перевод строки.
Например , в следующем примере мы ищем повторы слов несмотря на то ,
что возможны переводы строк.
$/ = ''; # read in more whole paragraph, not just one line
while ( <> )
{
while ( /\b([\w'-]+)(\s+\1)+\b/gi )
{ # word starts alpha
print "Duplicate $1 at paragraph $.\n";
}
}
Следующий код находит строку начинающуюся со слова 'From'
$str = 'From 123'; # read in more whole paragraph, not just one line
while ( /^From /gm )
{ # /m makes ^ match next to \n
print "leading from in paragraph $.\n";
}
Следующий код выводит содержимое параграфа , заключенного между START - END
$str="START 1
2
3
END";
while ($str =~ /START(.*?)END/sgm )
{ # /s makes . cross line boundaries
print "$1\n";
}
2. В: Как сделать , чтобы работала русская локаль для \w match ?
О: Использовать русскую локаль с помощью use locale;
Что-то типа
setlocale(LC_CTYPE, 'ru_RU.CP1251');
Смотрите perldoc perllocale
3. В: Как квотировать переменную внутри регеспа ?
О: В следующем примере символ 4 в строке будет заменен на набор четверок :
$string = "123 456 789";
$regex = "4";
$string =~ s/$regex/44444/;
4. В: Можно ли отдебажить регулярное выражение ?
О: Можно. Нужно использовать
use re 'debug';
Пример
use re 'debug';
$regex = 'Perl';
foreach ( qw(Perl Java Ruby Python) )
{
print STDERR "Trying $_...\n";
print STDERR "\t$_ is good!\n" if m/$regex/;
}
5. В: Как вырезать из файла комменты в стиле си ?
О: Например так :
perl -0777 -pe 's{/\*.*?\*/}{}gs' foo.c
6. В: Как правильно использовать т.н. квантификаторы - quantifiers (?, *, +, {}) ?
О: Квантификатор *? находит первое вхождение :
$s1 = $s2 = "I am very very cold";
$s1 =~ s/ve.*y //; # I am cold
$s2 =~ s/ve.*?y //; # I am very cold
7. В: Как работает \b ?
О: Пример :
"Perl" # no word char before P or after l
"Perl " # same as previous (space is not a word char)
"'Perl'" # the ' char is not a word char
"Perl's" # no word char before P, non-word char after "l"
Все эти 4 варианта эквивалентны /\bPerl\b/.
Следующие 2 строки соответствуют /\Bam\B/:
"llama" # "am" surrounded by word chars
"Samuel" # same
Следующие 2 строки не соответствуют /\Bam\B/
"Sam" # no word boundary before "a", but one after "m"
"I am Sam" # "am" surrounded by non-word chars
8: В: Где можно применять \G ?
О: Он используется для позиционирования.
Пример :
$_ = "1122a44";
my @pairs = m/(\d\d)/g ; # qw( 11 22 44 )
print "@pairs\n";
Здесь /g позволяет вычислить все пары чисел , в том числе и после символа a.
Если так :
my @pairs = m/\G(\d\d)/g; # qw( 11 22 )
или так :
while( m/\G(\d\d)/g )
{
print "Found $1\n";
}
то будут вычислены пары до символа a.
General Perl Language Issues
1. В: Каковы основные спецификаторы типов :
О: $ - числа , строки
@ - массивы
% - хеши
& - функции , процедуры , методы
* - указатели
<> - содержимое файла
\ - ссылка
2. В: Как проигнорировать возвращаемые значения ?
О: Использовать undef.
Пример :
($dev, $ino, undef, undef, $uid, $gid) = stat($file);
Или использовать список параметров :
($dev, $ino, $uid, $gid) = ( stat($file) )[0,1,4,5];
3. В: Можно ли блокировать варнинги ?
О: Можно
{
no warnings; # temporarily turn off warnings
$a = $b + $c; # I know these might be undef
}
4. В: Что такое extension ?
О: Это вызов скомпилированного си-шного кода из перл
См. perldoc perlxstut
5. В: Как создать структуру ?
О: Используйте хеш / ссылку на хеш :
$person = {}; # new anonymous hash
$person->{AGE} = 24; # set field AGE to 24
$person->{NAME} = "Nat"; # set field NAME to "Nat"
6. В: Как передать - и - вернуть из функции такие обьекты , как :
Function, FileHandle, Array, Hash, Method, Regex ?
О: Смотрите perldoc perlsub , раздел Pass by Reference , также perldoc perlref.
Стандартный тип переменной или функцию вертать просто - передавайте ссылку :
func( \$some_scalar );
func( \@some_array );
func( [ 1 .. 10 ] );
func( \%some_hash );
func( { this => 10, that => 20 } );
func( \&some_func );
func( sub { $_[0] ** $_[1] } );
Для передачи filehandle нужно использовать скаляр :
open my $fh, $filename or die "Cannot open $filename! $!";
func( $fh );
sub func {
my $passed_fh = shift;
my $line = <$passed_fh>;
}
Для передачи в функцию регеспа нужно , чтобы поддерживалась конструкция qr//.
В следующем примере в строке ищатся буквы d в обоих регистрах :
sub compare($$)
{
my ($val1, $regex) = @_;
my $retval = $val1 =~ /$regex/;
return $retval;
}
$match = compare("oldD Mconald", qr/d.*D/i);
Для передачи метода обьекта нужно делать примерно так :
call_a_lot(10, $some_obj, "methname")
sub call_a_lot {
my ($count, $widget, $trick) = @_;
for (my $i = 0; $i < $count; $i++) {
$widget->$trick();
}
}
7. В: Как создать статическую переменную ?
О: В перле нет статических переменных , есть лексические переменные ,
которые видимы внутри блока кода либо внутри одного файла .
BEGIN {
my $count = 1;
sub increment_count { $count++ }
sub return_count { $count }
}
Смотрите Persistent Private Variables в perlsub
8. В: Какая разница между local и my ?
О: local присваивает значение уже существующей переменной , находящейся в пределах видимости
my создает новую переменную
Пример :
sub visible {
print "$var\n";
}
sub dynamic {
local $var = 'local'; # new temporary value for the still-global
visible(); # variable called $var
}
sub lexical {
my $var = 'private'; # new private variable, $var
visible(); # (invisible outside of sub scope)
}
$var = 'global';
visible(); # prints global
dynamic(); # prints local
lexical(); # prints global
9. В: Как использовать switch ?
О: Пример :
$variable_to_test=2;
for ($variable_to_test)
{
if (/1/) { print"1\n"; } # do something
elsif (/2/) { print"2\n";} # do something else
elsif (/3/) { print"3\n";} # do something else
else { } # default
}
10. В: Как определить имя текущего модуля ?
О: my $packname = __PACKAGE__;
11. В: Как сделать большой блок комментариев ?
О: Нужно оформить блок :
=begin
...
=cut
12. В: Как удалить пакет в рантайме ?
О: Пример :
sub scrub_package
{
no strict 'refs';
my $pack = shift;
die "Shouldn't delete main package"
if $pack eq "" || $pack eq "main";
my $stash = *{$pack . '::'}{HASH};
my $name;
foreach $name (keys %$stash)
{
my $fullname = $pack . '::' . $name;
# Get rid of everything with that name.
undef $$fullname;
undef @$fullname;
undef %$fullname;
undef &$fullname;
undef *$fullname;
}
}
System Interaction
1. В: Как узнать название операционной системы ?
О: $^O
2. В: Как раскрасить вывод ?
О: use Term::ANSIColor;
print color("red"), "Stop!\n", color("reset");
print color("green"), "Go!\n", color("reset");
Или так :
use Term::ANSIColor qw(:constants);
print RED, "Stop!\n", RESET;
print GREEN, "Go!\n", RESET;
3. В: Как контролировать ввод с клавы ?
О: Использовать stty :
open(TTY, "+/dev/tty 2>&1";
$key = getc(TTY); # perhaps this works
# OR ELSE
sysread(TTY, $key, 1); # probably this does
system "stty -cbreak /dev/tty 2>&1";
Или так :
use Term::ReadKey;
ReadMode('cbreak');
$key = ReadKey(0);
ReadMode('normal');
4. В: Как очистить экран ?
О: system("clear");
5. В: Как пользователю ввести пароль ?
О: use Term::ReadKey;
ReadMode('noecho');
$password = ReadLine(0);
6. В: Как работать с портами ?
О: Это зависит от ОС. Для юникса нужно использовать /dev.
При этом могут возникнуть проблемы с lockfiles из-за множественного доступа.
Порт нужно открыть на апдэйт - см. open , perlfunc.
Используйте sysopen() , флаг O_RDWR|O_NDELAY|O_NOCTTY.
Для вывода символов нужно использовать select() и переменную $| для контроля autoflushing.
$oldh = select(DEV);
$| = 1;
select($oldh);
или так
use IO::Handle;
DEV->autoflush(1);
Для non-blocking input можно использовать код :
sub open_modem
{
use IPC::Open2;
my $stty = `/bin/stty -g`;
open2( \*MODEM_IN, \*MODEM_OUT, "cu -l$modem_device -s2400 2>&1");
# starting cu hoses /dev/tty's stty settings, even when it has
# been opened on a pipe...
system("/bin/stty $stty");
$_ = ;
chomp;
if ( !m/^Connected/ ) {
print STDERR "$0: cu printed `$_' instead of `Connected'\n";
}
}
7. В: Как запустить другой процесс 7
О: IPC::Open3, Parallel::Jobs, IPC::Run , POE
Или
system("cmd &")
или fork - смотрите fork , perlfunc, perlipc.
При этом STDIN, STDOUT , STDERR окажутся расшаренными для обоих процессов.
Прийдется обрабатывать сигналы SIGCHLD ,SIGPIPE , когда запущенный процесс завершится.
8. В: Как сделать паузу меньше секунды ?
О: Используйте select() - см. perlfunc , select.
9. В: Как обработать исключение ?
О: Использовать блок END , например :
END {
close(STDOUT) || die "stdout close failed: $!";
}
Можно использовать eval() - см. Signals , perlipc.
Можно использовать библиотеку exceptions.pl.
10. В: Как захватить STDOUT, STDERR из внешней команды ?
О: STDOUT :
use IPC::Open3;
use File::Spec;
use Symbol qw(gensym);
open(NULL, ">", File::Spec->devnull);
my $pid = open3(gensym, \*PH, ">&NULL", "cmd");
while( ) { }
waitpid($pid, 0);
STDERR :
use IPC::Open3;
use File::Spec;
use Symbol qw(gensym);
open(NULL, ">", File::Spec->devnull);
my $pid = open3(gensym, ">&NULL", \*PH, "cmd");
while( ) { }
waitpid($pid, 0);
И STDOUT , и STDERR :
use IPC::Open3;
use Symbol qw(gensym);
use IO::File;
local *CATCHOUT = IO::File->new_tmpfile;
local *CATCHERR = IO::File->new_tmpfile;
my $pid = open3(gensym, ">&CATCHOUT", ">&CATCHERR", "cmd");
waitpid($pid, 0);
seek $_, 0, 0 for \*CATCHOUT, \*CATCHERR;
while( ) {}
while( ) {}
11. В: Как запустить команду без помощи шелла ?
О: Нужно использовать open() с набором аргументов .
В следующем коде в искомом файле ищется подстрока :
$search_string="123";
@filenames=("filename");
open( GREP, "-|", 'grep', @opts, $search_string, @filenames );
chomp(@ok = );
close GREP;
12. В: Можно ли использовать перл для telnet или ftp session ?
О: Можно так смоделировать телнет :
use IO::Socket; # new in 5.004
$handle = IO::Socket::INET->new('www.perl.com:80')
or die "can't connect to port 80 on www.perl.com: $!";
$handle->autoflush(1);
if (fork()) { # XXX: undef means failure
select($handle);
print while ; # everything from stdin to socket
} else {
print while <$handle>; # everything from socket to stdout
}
close $handle;
exit;
13. В: Как открыть файл без его блокировки ?
О: Использовать флаги O_NDELAY , O_NONBLOCK
use Fcntl;
sysopen(FH, "/foo/somefile", O_WRONLY|O_NDELAY|O_CREAT, 0644)
or die "can't open /foo/somefile: $!":
14. В: Как проинсталлировать модуль CPAN ?
О: Стандарным путем :
$ perl -MCPAN -e shell
cpan shell -- CPAN exploration and modules installation (v1.59_54)
ReadLine support enabled
cpan> install Some::Module
Или вручную :
1 Распаковать архив
2. perl Makefile.PL
3. make
4. make test
5. make install
15. В: Какая разница между require и use ?
О: 1) do $file is like eval `cat $file`, except the former
1.1: searches @INC and updates %INC.
1.2: bequeaths an *unrelated* lexical scope on the eval'ed code.
2) require $file is like do $file, except the former
2.1: checks for redundant loading, skipping already loaded files.
2.2: raises an exception on failure to find, compile, or execute $file.
3) require Module is like require "Module.pm", except the former
3.1: translates each "::" into your system's directory separator.
3.2: primes the parser to disambiguate class Module as an indirect object.
4) use Module is like require Module, except the former
4.1: loads the module at compile time, not run-time.
4.2: imports symbols and semantics from that package to the current one.
16. В: Как добавить новый каталог в список module/library ?
О: use lib $directory;
|