利用者:Senseequal/Perl/関数

出典: フリー教科書『ウィキブックス(Wikibooks)』

関数と演算子の違い[編集]

print()は関数です。printは演算子です。このように、カッコを付けたものを関数、付けないものを演算子といいます。

printf[編集]

print "朝", int($x), "時に起きて、", int($y), "時に昼寝して、夜", int($z), "時に寝た。\n";

このような見にくいコードを、

printf "朝%d時に起きて、%d時に昼寝して、夜%d時に寝た。\n", $x, $y, $z;

このように見やすくするときに使います。

printfには$\が効かないので、ご注意を。

sprintf[編集]

十進法を十六進法に変換するときに使います。

my $hex = sprintf "%X", 16; # 10

substr[編集]

先頭/末尾1文字を見るときに使います。

while (<$fh>) {
    next if substr($_, 0, 1) eq '#';
    # ...
}

しかし、

while (<$fh>) {
    next if /^#/;
    # ...
}

こちらの方がタイプ量が少なくて済むという理由で好まれる場合もあります。

正規表現は遅いのですが、実生活に支障が出るほど遅いわけでもないからです。

上級者ほど後者の書き方を好む傾向にあります。

substrをタイプするのは面倒だが、正規表現を何度もコンパイルしたくないという場合は、

while (<$fh>) {
    next if /^#/o;
    # ...
}

oオプションを指定することもあります。

末尾1文字を切り出すには、

my $chop = substr $str, -1;

とします。

my $chop = chop $str;

は破壊的なため、遅い可能性があります。

map[編集]

後置forが使えず、かつ入れ子forより相応しい場合に使います。

つまり、手間を省いて一行で書きたい場合(あるいは結果が重要な場合)。

grepと同じく様々に使われます。

シュワルツ変換など。

warn[編集]

デバッグ時、あるいはprintの最後に\nを入れるのが面倒な場合に使います。

our $PI = 3.141592653589793;
# ...
warn $PI;
#!/usr/bin/perl
warn time;

die[編集]

openに失敗したときに使います。

open my $log, '<:utf8', "$logdir/$logfile"
    or die $!;

pack/unpack[編集]

使いません。

split[編集]

一文字ずつ処理したい場合に使います。

my @chars = split //, $str;

binmode[編集]

utf8文字列を出力する可能性があるときに使います。

use utf8;
use Encode qw(find_encoding);
binmode STDOUT, ':utf8';
my $utf8 = find_encoding 'UTF-8';
warn $utf8->decode($0);

lc/lcfirst/uc/ucfirst[編集]

使いません。ただし、

print 1 if "apPlE" =~ /^APPLe\z/i;

よりも、

print 1 if lc "ApPlE" eq lc "aPPlE";

の方が良いとの意見はあります。

do[編集]

my $slurp = do { local $/; <$fh> };

grep[編集]

必要に応じて使い方は様々です。

grep { $_ ne 'a' and $_ ne 'b' } よりも grep !/a|b/, という形がよく使われます。

readdirする機会が多ければ、頻繁に使うでしょう。

length[編集]

文字数が必要な場合、長さに何らかの制限を設けたい場合、などか。

hex/chr/oct/ord[編集]

特殊な用途で使います。これらを使う用途では、packやunpackやvecやsubstr、sprintfも使うかもしれません。

chomp[編集]

getsした直後。

my @data = <>;
chomp @data;

whileとの兼ね合いも見られる。

while (<>) {
    chomp;
    # ...
}

入力の最後に\nが付加されるとは、駆け出しの頃は思いも寄りませんでした。

sort[編集]

数字順にしたいとき。

@files = sort { $a <=> $b } @files;

数字順 or 文字列順という場合は事前に分岐するか、あるいはno warningsを使うか。

qw[編集]

非オブジェクト指向モジュールから自動的にはインポートされない関数をインポートする場合。

use CGI::Carp qw/fatalsToBrowser/;

あるいは、自動的にインポートされるものの、明示的に指定しておきたい場合。

use File::Basename qw/basename/;

あるいは、自分の名前空間を汚されたくないので何から何までインポートしたくない場合。

use Encode qw(from_to);

何もインポートしたくない場合は、単なる空リストを渡します。

use List::Util ();
$\ = "\n";
print for List::Util::shuffle(@INC);

scalar[編集]

localtimeを文字列にしたい場合。

print scalar localtime;

日本標準時 (UTC+09:00) を得るには、

print gmtime time + 9 / 60 / 60;

すなわち

print gmtime time + 32400;

とします。localtimeは、海外のサーバではJSTを返さないでしょう。

time2dhms[編集]

秒を日時分秒に変換する関数です。私が発明しました。

sub time2dhms($) {
    my $time = shift;
    return unless defined $time;
    my $d = int $time           / 86200;
    my $h = int $time % 86200   / 3600;
    my $m = int $time % 3600    / 60;
    my $s =     $time % 60;
    return ($d, $h, $m, $s);
}

これを日本語に変換するには、

sub time2ja($) {
    my $time = shift;
    return unless defined $time;
    return '0秒' unless $time;
    my ($d, $h, $m, $s) = time2dhms $time;
    my $str;
    $str .= "${d}日"     if $d;
    $str .= "${h}時間"   if $h;
    $str .= "${m}分"     if $m;
    $str .= "${s}秒"     if $s;
    return $str;
}

こんな感じです。