基本
たまに整理するけど、基本的にでたらめなメモ。
クォート
#'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 |
- 404 Blog Not Found:日本語で確実に使える約物 via Unicode
http://blog.livedoor.jp/dankogai/archives/50837229.html
全然関係ないけど、改行っぽい文字→「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 |
- 404 Blog Not Found:Unicode - 似た文字同士にご用心
http://blog.livedoor.jp/dankogai/archives/51043693.html
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 |
半角カナ→全角
- 404 Blog Not Found:perl - で全角半角変換をモダンに行う
http://blog.livedoor.jp/dankogai/archives/51220946.html
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/;