kdoc - Perl

  • 作成日:2006-09-05 15:01:55
  • 修正日:2012-01-13 12:27:27

基本

↑ページトップへ

たまに整理するけど、基本的にでたらめなメモ。

クォート

#'abc'
q{abc}
#"abc_$d"
qq{abc_$d}
#`uptime`
qx{uptime}
#(1, 2, 3)
qw{1 2 3}
#正規表現
qr/PATTERN/option
#/PATTERN/
m{PATTERN}
#s/PATTERN//
s{PATTERN}{}
#tr///
tr{}{}

数値

#整数部分
my $res = int(1.5); #--> 1
my $res = int(-1.5); #--> -1
#四捨五入
my $res = int($num + 0.5);
#サイコロ
my $res = int(rand 6) + 1;
#絶対値
my $res = abs($num);

2進数/8進数/16進数

#2進数(先頭に0b)
my $num_bin = 0b1111;
#8進数(先頭に0)
my $num_oct = 0777;
#16進数(先頭に0x)
my $num_hex = 0xFFFF;
#16進数→10進数
my $aaa = hex('fa7a');
#10進数→16進数
my $bbb = sprintf("%lx", '367156');
#文字→16進数
my $hex = unpack("H*", 'あ');
#asciiから
my $text = chr(29);
#asciiへ
my $ascii = ord('あ');

or, and, &&, ||

  • orとandはPerl5から導入で、こちらを推奨。
  • &&/||の方が、or/andの方が優先順位が低い。

&&/||じゃないとだめな場合。

my $a = test() || test() ? 0 : 1;
#上記をorでやりたいなら、
my $a = ( test() or test() ) ? 0 : 1;
sub aaa {
  my $aaa = shift || 1;
}
#上記をorでやりたいなら、
sub aaa {
  my $aaa = (shift or 1);
}

Perl 5.10なら

my $aaa = $bbb // 1;
#以下と同じ
my $aaa = defined $bbb ? $bbb : 1;

printf/sprintf

my $num = 37;
my $formated = sprintf "%05d", $num; # --> 00037
#符号付き整数として解釈し、ゼロで埋めて8桁に
%08d
#浮動小数点として解釈し、小数点以下2位まで(ほぼ四捨五入=0.725が0.72499999…等)
%.2f
#文字列として解釈し、右詰めにしてスペースで埋める
%5s
#文字列として解釈し、左詰めにしてスペースで埋める
%-5s
#文字列として解釈し、右詰めにしてゼロで埋める
%05s

配列

my $aaa = (0 .. 9);
my $bbb = ('A' .. 'Z');
#要素数
my $count = @a;
#最後の要素
my $last = $ary[-1];
#末尾に追加
push @ary, $a;
#先頭を削除
shift @ary;
#末尾を削除
pop @ary;
#先頭に追加
unshift @ary;
my $first = shift @ary;
my $last = pop @ary;
#スライス
my @res = @ary[3, 7];
my @res = @ary[0 .. 4];
#スライス(代入)
my @ary[2, 3] = ('b', 'c');
#splice(5要素目から3つ取得)
my @res = splice @ary, 4, 3;
#splice(5要素目に@addを追加)
my @res = splice @ary, 4, 0, @add;

ハッシュ

#KeyとValueを入れ替え
%hash = reverse %hash;
#Keyの数
my @ary = %hash;
my $countPre = @ary;
my $count = $countPre / 2;
-or-
my $countPre = @ary = %hash;
-or-
my $count = scalar keys %hash;
#結合
my %ccc = (%aaa, %bbb);
#キーと値の削除
delete $hash{$key};
#キーの存在チェック
if(exists $hash{$key}){
}
#値の定義チェック(0は「定義」、undefは「未定義」)
if(defined $hash{$key}){
}
#ループ
foreach my $key(keys %hash){
}
foreach my $value(value %hash){
}
while( my($key, $value) = each %hash){
}
#キー順にループ
foreach my $key( sort {$hash{$b} <=> $hash{$a} } keys %hash ){
}

ファイル情報 stat

↑ページトップへ

if( -f $path ){
  my $file_size = -s _; #「_」にキャッシュされてる(stat cache)
}
($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size,
  $atime, $mtime, $ctime, $blksize, $blocks) = stat($filename);
# statはsymblic linkを解決してリンク先ファイルの情報を取得。lstatはリンクそのものの情報を取得。
0 dev device number of filesystem ボリュームごとに固有に割り当てられるID
1 ino inode number そのボリューム内で固有に割り当てられるID
2 mode file mode (type and permissions) ファイルの種類とパーミッション
3 nlink number of (hard) links to the file そのノードにハードリンクがいくつあるか
4 uid numeric user ID of file's owner ファイルの所有者ID
5 gid numeric group ID of file's owner ファイルのグループID
6 rdev the device identifier (special files only) デバイス識別子(ほとんど使われない項目)
7 size total size of file, in bytes ファイルサイズ
8 atime last access time in seconds since the epoch 最後にアクセスされた(readされた)時間(エポック秒)
9 mtime last modify time in seconds since the epoch データ最終更新時間(エポック秒)
10 ctime inode change time in seconds since the epoch (*) メタデータも含めた最終更新時間(エポック秒)
11 blksize preferred block size for file system I/O このファイルシステムでの1ブロックのサイズ
12 blocks actual number of blocks allocated このファイルシステムでいくつのブロックを使用しているか

※ (getpwnam($uid))[2]でユーザ名、(getgrnam($gid))[2]でグループ名が取得可能。

OOを希望の場合は、Fili::stat を使用。

時間

↑ページトップへ

エポック秒へ。

use POSIX qw/mktime/;

sub date2time {
  my ($YYYY, $MM, $DD, $hh, $mm, $ss) = @_;
  return mktime($ss, $mm, $hh, $DD, $MM - 1, $YYYY - 1900);
}

open

↑ページトップへ

openプラグマ

#バイナリモード
:bytes
#テキストモード
:crlf
use open IN => ':encoding(cp932)', OUT => ':utf8';
use open IO => ':encoding(euc-jp)';
use open ':utf8';
#以下と同じ
use open IO => ':utf8';

すでに開かれているファイルハンドルに対して指定。

binmode STDOUT, ':utf8';
binmode IN, ':encoding(shiftjis)';

Encode::Supported

ascii
iso-8859-1 #latin1
utf8
UTF-16
UTF-16BE
UTF-16LE
UTF-32
UTF-32BE
UTF-32LE
euc-jp
shiftjis
cp932
macJapanese
7bit-jis
iso-2022-jp #RFC1468
iso-2022-jp-1 #RFC2237

パイプへ
第二引数に '|-'

open my $pipe, '|-', 'more';
print $pipe 'aaaa';
close $pipe;

パイプから
第二引数に '-|'

open my $pipe, '-|', 'dir';
while(my $line = <$pipe>){
  print $line;
}
close $pipe;

やり方

↑ページトップへ

ファイル読み込み

# 一括読み込み
my $path = '/path/to/file.txt';
open my $fh, '<:utf8', $path or die qq|open($path) failed: $!|;
my $data = do{ local $/; <$fh> };
close $fh;

パスワード作成

sub makePassword{
  my $num = shift;
  my $pwd;
  $pwd .= ('a' .. 'z', 0 .. 9)[int(rand(36))] while $num -- > 0;
  return $pwd;
}

ヒアドキュメント中のプログラム

$out = <<HTML;
<html>
<head>
<title>${………}</title>
</head>
<body>
HTML

数字列とそれ以外の文字を"@"で分ける

my $text = 'あいうabcかきくdef';
$text =~ s/(\D*)(\d+)(\D*)/$1@$2@$3/g;

文字変換

#すべて小文字へ
$string =~ tr/A-Z/a-z/;
#a-z以外の文字を削除
$string =~ tr/a-z//cd;

合計

$sum += $_ for @numbers;

substr

#先頭から2byte
my $res = substr($a, 0, 2);
#末尾5文字
my $res = substr($a, -5);
#末尾5文字を削除
substr($a, -5) = '';
#末尾2byteを削除した残り
my $res = substr($a, 0, -2);
#先頭3文字を削除した残り
my $res = substr($a, 3);
#19730307の場合
my $YY = substr $date, 0, 4;
my $MM = substr $date, 4, 2;
my $DD = substr $date, 6, 2;

grep

my @results = grep $expression, @inputList;
my $count = grep $expression, @inputList;
my @results = grep $_ > 10, @in;
my @results = grep /^\d$/, @in;
my @results = grep test($_), @in;
sub test{
 …
 return 1;
}
my @results = grep {…} @in;
#@inの前のカンマなし。{…}ではreturnは書かない。
#空要素削除
my @results = grep length $_, @in;
#空白要素削除
my @results = grep {
  if(/^¥s+$/){
    $_ = undef;
  }
  $_;
} @in;

map

my @results = map function($_), @in;
my @results = map {...} @in;

ソート

↑ページトップへ

#ASCII
my @res = sort @list;
#数値
my @res = sort {$a <=> $b} @list;
#数値逆順
my @res = sort {$b <=> $a} @list;
#文字列
my @res = sort {$a cmp $b} @list;
#文字列逆順
my @res = sort {$b cmp $a} @list;
#インデックス値(ソート前の3番目はソート後には何番目?)
my @res = sort {$list[$a] <=> $list[$b]} 0 .. $#list;
#インデックス値(ソート前の3番目はソート後には何番目?)文字列
my @res = sort {$list[$a] cmp $list[$b]} 0 .. $#list;
#複数項目で
my @res = sort { $b->{age} <=> $a->{age} or $a->{name} cmp $b->{name} } @list;

ファイルを更新日時順にソート

↑ページトップへ

古い順

my $dir = '/Users/officek/Desktop/test';
$dir =~ s/\/$//;
opendir DIR, $dir;
my @files =
    map { $_->[0] }
    sort { $b->[1] <=> $a->[1] }
    map { [ $_, -M "$dir/$_" ] }
    grep ( /^[^.]/, readdir DIR );
close DIR;

for my $file(@files){
    my ($ss, $mm, $hh, $DD, $MM, $YY, $wday, $yday, $isdst) = localtime( ( stat qq|$dir/$file| )[9] );
    $YY += 1900;
    $MM ++;
    printf "%s\t%d-%02d-%02d %02d:%02d:%02d\n", $file, $YY, $MM, $DD, $hh, $mm, $ss;
}

新しい順

    sort { $a->[1] <=> $b->[1] }

変数

↑ページトップへ

#Perlのバージョン(バージョン+パッチレベル/100)
#use Englishした場合は、$PERL_VERSIONでアクセス可能。
$]
#マッチング
$`(前)←$&(そのもの)→$'(後)
#実行中のファイル名
$0

マッチング

↑ページトップへ

#後ろタブのある単語にマッチ($&にタブは含まれない)
/\w+(?=\t)/
#後ろにbarがないfooにマッチ
/foo(?!bar)/
#グループ化(後方参照用に記憶される)
/Windows (Me|Xp)/
#後方参照を行なわないグループ化
/Windows (?:Me|Xp)/
($year, $month, $day) = (/^(\d\d\d\d)(\d\d)(\d\d)$/);
#下記よりも
/a|b|c/
#下記の方が高速
/[abc]/
#マッチしたものが配列に入る
my @match = ($text =~ /^(\d+)\-(\d+)\-(\d+)$/);
#マッチした個数(例: タブの個数)
my $count = ($text =~ tr/\t/\t/);

進数変換

↑ページトップへ

#16進数→10進数
$dec = hex( 0x1AB );
#10進数→16進数
$hex = sprintf("%lx", 16);
#10進数→8進数
$oct = sprintf("%lo", 10);
#8進数→10進数
$dec = oct 10;

情報

↑ページトップへ

#バージョン/パッチ情報等
$ perl -v
#モジュール検索
find `perl -e 'print "@INC"'` -name '*.pm' -print
find `perl -e 'print "@INC"'` -name 'Jcode.pm' -print

モジュール一覧

use ExtUtils::Installed; # perl 5.005からOK

my $ei = ExtUtils::Installed->new;
for my $module($ei->modules){
  printf "%s   %s\n", $module, $ei->version($module);
}

特殊リテラル

↑ページトップへ

#プログラムの論理的な終わり(この文字列以降は解釈されない)
__END__
#現在のファイル名
__FILE__
#現在の行番号
__LINE__
#現在のパッケージ名
__PACKAGE__

__END__以降の行は<DATA>で読み込むことができる。

リファレンス

↑ページトップへ

調べる

ref $aaa;
#返り値→SCALAR / CODE / ARRAY / HASH

スカラーのリファレンス/デリファレンス

#$scalar
my $ref = \$scalar;
#\$scalarのデリファレンス
${$ref}; $$ref;

配列のリファレンス/デリファレンス

#@aryのリファレンス
my $ref = \@ary;
#\@aryのデリファレンス
@{$ref}; @$ref;
#配列の要素へアクセス
${$ref}[1]; $$item[1]; $ref->[1];
#2次元、3次元なら
$ref->[1]->[3]->[0];

ハッシュのリファレンス/デリファレンス

#%hashのリファレンス
my $ref = \%hash;
#デリファレンス
my $name = ${$ref}{'name'}; $$ref{'name'}; $ref->{'name'};
#ハッシュ全体
my @key = keys %{$ref}; %$ref;

サブルーチンのリファレンス/デリファレンス

#⊂のリファレンス
$ref = \⊂
#デリファレンス
&{$ref}('yugo');
&$ref('yugo');
$ref->('yugo');

無名配列

my $fruits = ['pineapple', 'papaya', 'mango'];
#下記と同義
my $fruits;
{
 my @secret_variable = ('pineapple', 'papaya', 'mango');
 $fruits = \@secret_variable;
}

無名ハッシュ

my $ref_to_yugo_info = {
 name => 'yugo',
 hat => 'White',
 shirt => 'Red',
};
#下記と同義
my $ref_to_yugo_info;
{
 my %yugo_info = (
 name => 'yugo',
 hat => 'White',
 shirt => 'Red',
 );
 $ref_to_yugo_info = \%yugo_info;
}

無名サブルーチン

my $ref_sum = sub{
  my $total;
  for my $num(@_){
    $total += $num
  }
  return $total;
}
#使う
my $total = $ref_sum->( 1, 2, 3 );

リファレンスの中身

use Data::Dumper;
#リファレンスを渡す
print Dumper($ref);
#utf8対応
use Data::Dumper;
{ no warnings; package Data::Dumper; sub qquote { return shift; } }
$Data::Dumper::Useperl = 1;
print Dumper $k;

複数行コメントアウト

=for comment
コメントアウトされる
=cut

utf8対応

use strict;
use warnings;
#ソースがutf8
use utf8;
use Encode;
#IN/OUTをutf8
use open IO => ":utf8";
#標準出力をutf8
binmode STDOUT, ":utf8";

継承

use base qw/Yugo::Common Yugo::Html/;

メソッドのオーバーライド

sub speak{
    my $class = shift;
    $class->SUPER::speak(@_);
}

constant

use constant LIB_DIR => '/home/yugo/lib';
use lib LIB_DIR;

Perl with Macintiosh メモ

↑ページトップへ

use Text::Iconv;

my $path = $ARGV[0];
#特殊なNFDなUTFから通常のUTF-8へ
my $path_nfc = Text::Iconv->new('UTF-8-MAC', 'UTF-8')->convert($path);
#UTF-8フラグが落ちてしまったので、再度たてる
my $path_nfc_flagged = Encode::decode('UTF-8', $path_nfc);

#まとめると以下
#$path = Encode::decode('UTF-8', Text::Iconv->new('UTF-8-MAC', 'UTF-8')->convert($path));

Windows ActivePerl メモ

↑ページトップへ

ファイルの入出力は、UTF-8/LFにしたい。
ソースファイルは当然UTF-8にしたい。

use strict;
use utf8;
use open IO => ":unix:utf8"; #:unixでLFに、:utf8でUTF-8に。
binmode STDIN,  ":crlf:encoding(cp932)";
binmode STDOUT, ":crlf:encoding(cp932)";
binmode STDERR, ":crlf:encoding(cp932)";

binmodeの指定は以下のようにしても。

map { binmode($_, ":crlf:encoding(cp932)") } qw/STDIN STDOUT STDERR/;

デバッグ

↑ページトップへ

# 起動
perl -d test.pl
# ブレークポイント
$DB::single = 1;
# 条件付ブレークポイント
if ($num == 2) { $DB::single = 1 }
# 警告をキャッチしてブレークポイントしかける
$SIG{__WARN__} = sub {
    $DB::single = 1;
};
  • q : 終了
  • n: 次の行実行
  • s: 次のステップ実行(サブルーチンの中も)
  • c: ブレークポイントまで実行
  • c 5: 5行目の直前まで実行
  • p $num: 変数の中身を表示
  • x \%hash: 変数の中身を表示(リファレンス渡し)
  • v: 周辺の行を表示
  • .: 現在の行を表示
  • (任意の文を実行させることも可能)

ホスト名の取得

↑ページトップへ

use Sys::Hostname qw/hostname/;

my $host = hostname();

関数の展開

↑ページトップへ

ヒアドキュメントでは使用不可。

print "あいうえお.$Class->aaa.かきくけこ。";

数値か文字列か

↑ページトップへ

[perl内部的に数値か文字かを判別する]

sub num_or_str{
  my $v = shift;
  if( ($v ^ $v) eq '0' ){
    return '数値';
  }
  else{
    return '文字列';
  }
}

sub is_num{
  my $v = shift;
  if( ($v ^ $v) eq '0' ){
    return 1;
  }
  return 0;
}

パス/ファイル名/ディレクトリ

↑ページトップへ

use File::Basename;
my($base_name, $dir_name) = fileparse($path);
my $base_name = basename($path);
my $dir_name = dirname($path);

文字コード/文字セット関係

↑ページトップへ

入ったきたものを decode して 内部ではUTF-8フラグ付きで扱い、外へ出す時に encode する。

UTF-8で書かれたTextをEUC-JPに変換し、変換しきれないものは実体参照に

404 Blog Not Found:perl - Encode 中級

use Encode;
while(<>){
  my $utf8 = decode_utf8($_);
  print encode('eucjp', $utf8, Encode::FB_HTMLCREF);
}
# Encode::FB_HTMLCREF だと10進数、Encode::FB_XMLCREF にすると16進数
# Encode::FB_PERLQQ にすると、\x{XXXX} 表記へ

※Encode 2.13(2006-01-14リリース) 以上では「FB_」不要

encodeを高速に

# 通常
my $str = Encode::encode('Shift_JIS', $str);
# 上記だと「Shift_JIS」あるいは「shiftjis」「sjis」等を同じものとして扱うために名前解決をしている。
# しなくていいようにするには以下。
my $enc = find_encoding('Shift_JIS');
my $str = $enc->encode($str);
# find_encoding で返ってくるのはオブジェクト(正規化された名前ではなく)

Macのファイル名/パスの「UTF-8-MAC」を「UTF-8」へ

Mac OSのファイル名は、UTFのNFDだけど、一部の領域はNFCというちょっと特殊なもの(=UTF-8-MAC)。

  • U+2000 - U+2FFF
  • U+F900 - U+FAFF
  • U+2F800 - U+2FAFF
use Text::Iconv;

my $mac_path = 'あいうえお'; #通常はディレクトリを開いたりして取得
my $normal_utf8_text = Text::Iconv->new('UTF-8-MAC', 'UTF-8')->convert($mac_path);

あるいは、Encode::UTF8Mac - tomi-ruメモから Encode::UTF8Mac を利用。

use Encode;
use Encode::UTF8Mac;

my $path = Encode::decode('utf-8-mac', $path);

#encodeは、utf8(NFC)のままでも、システムが自動変換してくれるので、Encode::encode('utf-8-mac', $path) はしなくていい(してもいいけど)。

MIMEエンコード

# Perl 5.8.6以降?
use Encode;
my $subject = 'さぶじぇくと';
my $encoded = encode('MIME-Header-ISO_2022_JP', $subject);

UTF-8環境からShift_JIS/ISO-2022-JP/EUC-JPへ出力するときに文字化けしないように整える

cp932(Windows)環境由来のff5e, 2225, ff0d, ffe0, ffe1, ffe2が混入していると、(cp932以外の)Shift_JIS/ISO-2022-JP/EUC-JPへ変換する際に「マッピングできない」と言われるので、それぞれ変換できるものに置換して整えておく。

$text =~ tr/[\x{ff5e}\x{2225}\x{ff0d}\x{ffe0}\x{ffe1}\x{ffe2}]/[\x{301c}\x{2016}\x{2212}\x{00a2}\x{00a3}\x{00ac}]/;

逆に、整えてあるテキストをcp932へ変換する際には、301c, 2016, 2212をff5e, 2225, ff0dへ戻しておく(00a2, 00a3, 00acはcp932への変換で変換される)。

(my $for_cp932 = $text) =~ tr/[\x{301c}\x{2016}\x{2212}]/[\x{ff5e}\x{2225}\x{ff0d}]/;

cp932なテキストをUTF-8にしたいだけなら変換するだけでいい。
いくつかの文字を揃えておきたいなら、

(my $fixed = $cp932) =~ tr/[\x{ff5e}\x{2225}\x{ff0d}]/[\x{301c}\x{2016}\x{2212}]/;

これをcp932へ戻す必要があるなら、

(my $for_cp932 = $text) =~ tr/[\x{301c}\x{2016}\x{2212}]/[\x{ff5e}\x{2225}\x{ff0d}]/;

上記もろもろとは別に、815Cの全角ダッシュについては、HORIZONTAL BARに揃えておいた方が良いかも(2014のEM DASHだとWindows XP上のTeraPadで「?」になったので)。

$text =~ s/\x{2014}/\x{2015}/g;
Shift_JIS Windows  
8160 ff5e FULL WIDTH TILDE 301c WAVE DASH
816B 2225 PARALLEL TO 2016 DOUBLE VERTICAL LINE
817C ff0d FULLWIDTH HYPHEN-MINUS 2212 MINUS SIGN
8191 ffe0 FULLWIDTH CENT SIGN 00a2 ¢ CENT SIGN
8192 ffe1 FULLWIDTH POUND SIGN 00a3 £ POUND SIGN
81CA ffe2 FULLWIDTH NOT SIGN 00ac ¬ NOT SIGN
Shift_JIS Mac/Vistaの変換表 Unicode/cp932の変換表
815C 2014 EM DASH 2015 HORIZONTAL BAR

全然関係ないけど、改行っぽい文字→「b5;」(U+21B5)

横棒関係
002D - HYPHEN-MINUS
02D7 ˗ MODIFIER LETTER MINUS SIGN
207B SUPERSCRIPT MINUS
208B SUBSCRIPT MINUS
2010 HYPHEN
2011 NON-BREAKING HYPHEN
2012 FIGURE DASH
2013 EN DASH
2014 EM DASH
2015 HORIZONTAL BAR
2212 MINUS SIGN
FE63 SMALL HYPHEN-MINUS
FF0D FULLWIDTH HYPHEN-MINUS

PerlのバージョンとEncodeのバージョン

perl-5.8.1 Encode-1.9801
perl-5.8.2 Encode-1.9801
perl-5.8.3 Encode-1.99
perl-5.8.4 Encode-1.99_01
perl-5.8.5 Encode-2.01
perl-5.8.6 Encode-2.08
perl-5.8.7 Encode-2.10
perl-5.8.8 Encode-2.12

半角カナ→全角

use Lingua::JA::Regular::Unicode qw/katakana_h2z/;

$v = katakana_h2z($v);

Perl IO レイヤ

↑ページトップへ

#以下は同じ
use open ':utf8';
use open IO => ':utf8';
use open IN => ':utf8', OUT => ':utf8';

#バイナリモードとテキストモード
:bytes
:crlf #CRLFを改行へ変換

#
:unix #Unixのread(), write()等を使用。バッファリングなし。どのプラットフォームでも常にO_BINARY。
:win32 #Windowsネイティブのハンドルを使用。5.10.0でバグあり?
:raw #各レイヤの変換を無効にして、バイナリデータをそのまま扱う。

use Carp

↑ページトップへ

use Carp;

  • die() → croak()
  • warn() → carp()

いろいろ

↑ページトップへ

# 未定義なら設定
$q->{mode} ||= 'default';
#ひらがな
my @hiragana = map { chr } (ord('ぁ') .. ord('ん'));

改行コードの統一

$v =~ s/\x0D\x0A|\x0D|\x0A/\n/g;

#以下の2行でやった方が圧倒的に速い
$v =~ s/\x0D\x0A/\n/g;
$v =~ tr/\x0D\x0A/\n\n/;

↑ページトップへ