ファイル名生成(拡張子だけ変更)
$filename = (split(/\./,$ARGV[0]))[0];
$filename = $filename.".csv";
1が立っているbit数を数える
sub bitcount
{
# 1の数を数える
$bits = $_[0];
$bits = ($bits & 0x55555555) + ($bits >> 1 & 0x55555555);
$bits = ($bits & 0x33333333) + ($bits >> 2 & 0x33333333);
$bits = ($bits & 0x0f0f0f0f) + ($bits >> 4 & 0x0f0f0f0f);
$bits = ($bits & 0x00ff00ff) + ($bits >> 8 & 0x00ff00ff);
return ($bits & 0x0000ffff) + ($bits >>16 & 0x0000ffff);
}
実行環境におけるlocaltimeの取得方法
# 実行環境のlocaltimeを取得(普通はJST)
my $now = time();
my $off = (timegm(localtime($now))-timegm(gmtime($now)))/60;
printf( "%+03d:%02d\n", $off/60, $off%60 );
時刻フォーマットの読み込み方
$utc0にyy/mn/dd hh:mm:ssのテキストが入っている
$utc0 =~ /(\d+)\/(\d+)\/(\d+) (\d+):(\d+):(\d+)/;
my $yy = $1;
my $mn = $2;
my $dd = $3;
my $hh = $4;
my $mm = $5;
my $ss = $6;
フォルダ内にあるファイルリストの取得
exe化にも問題にならないので、良い感じ。glob()はエラーになってしまう。plのままなら、globが良い。
opendir(DIRHANDLE, "./");
my $cnt = 0;
foreach(readdir(DIRHANDLE)){
next if /^\.{1,2}$/; # '.'や'..'をスキップ
$file[$cnt] = $_;
$cnt++;
}
closedir(DIRHANDLE);
perlで符号付き型変換
# 16進を符号付き10進に変換する
sub dec2dec()
{
my $val = shift;
my $bit = shift;
# 範囲確認
#if ( ($val > (2**($bit-1)-1)) or ($val < -(2**($bit-1)))) {
# die "$valは指定されたビット数$bitでは2の補数表現ができません。?n";
#}
if($val > (2**($bit-1)-1))
{
# 負値なら
return $val - (2**$bit);
}else{
# 正値なら
return $val;
}
}
改行コード0x0Dを付けない
Windowsでは、改行コードが0x0D0Aであるため、テキストデータでは、自動で改行コードが変換される。しかし、バイナリ出力では0x0Aを出力しようとすると、勝手に0x0D0Aに変換されてしまうという弊害となる。そこで、この自動変換を止めるには、下記のようにすれば良い。
open OUT, ">:raw", "data1.txt";
0x0A を出力する時に 0x0A → 0x0D, 0x0A という置換をするには、↓か、無印
open OUT, ">:crlf", "data2.txt";
テキストをバイナリに変換する
perl内のテキストデータをそのままバイナリに変換する。もちろん、テキストデータは16進数内のテキスト[A-F\d]である必要がある。
foreach(@line)
{
my $disp = $_;
# 改行コード削除
$disp =~ s/\s//gi;
# 出力
print OUT pack("H*", $disp);
}
バイナリデータ読み込み
読み込みだけでなく、書き込みの時も同様。ファイルポインタをbinmodeにする必要がある。
以下の方法は読み込むデータが大きい時には使えない(Out of memory!と言われる)
open INFILE, "<$ARGV[0]" or die "file open error: $!";
# バイナリモードに変更
binmode INFILE;
for( my $i = 0; $i < 4; $i++ )
{
my $buf;
# 名前と得点を読み込む
#read INFILE, $buf, 1;
sysread(INFILE, $buf, -s INFILE);
# $bufをアンパック
my @temp = unpack 'C*', $buf;
my $ch = unpack("H2", pack("C", $temp[0]));
my $disp = sprintf("0x%02X\n",$temp[0]);
print $disp;
}
# ファイルを閉じる
close INFILE;
そのような場合は、1Byteずつ読み込んで処理する
# 対象のファイルオープン
open INFILE, "<$ARGV[0]" or die "file open error: $!";
# バイナリモードに変更
binmode INFILE;
# 出力ファイル
open OUT,">$str1" or die "file open error 2: $!";
$cnt = 1;
while(1)
{
last if undef == read(INFILE, $code, 1);
$data = sprintf("%02X", unpack("C",$code) );
#$data = unpack("W",pack('C',hex($data)));
print OUT $data;
}
平均値/標準偏差
# 平均値算出
for($i=0;$i<$cnt;$i++)
{
# x行目の処理
$ave_cnt[$i] = 6;
$ave[$i] = 0;
# 平均値の個数集計
if(int($AZ00[$i]) == 0){$ave_cnt[$i]--;}else{$ave[$i] += $AZ00[$i];}
if(int($AZ10[$i]) == 0){$ave_cnt[$i]--;}else{$ave[$i] += $AZ10[$i];}
if(int($AZ15[$i]) == 0){$ave_cnt[$i]--;}else{$ave[$i] += $AZ15[$i];}
if(int($AZ20[$i]) == 0){$ave_cnt[$i]--;}else{$ave[$i] += $AZ20[$i];}
if(int($AZ30[$i]) == 0){$ave_cnt[$i]--;}else{$ave[$i] += $AZ30[$i];}
if(int($AZ40[$i]) == 0){$ave_cnt[$i]--;}else{$ave[$i] += $AZ40[$i];}
# その行の個数が0ならaveも0
if($ave_cnt[$i] == 0){
$ave[$i] = 0;
}else{
$ave[$i] = $ave[$i]/$ave_cnt[$i];
}
}
# 標準偏差算出
for($i=0;$i<$cnt;$i++)
{
# x行目の処理
$std[$i] = 0;
# 標準偏差の処理 値が0なら飛ばす
if(int($AZ00[$i]) != 0){$std[$i] += ($AZ00[$i] - $ave[$i])*($AZ00[$i] - $ave[$i]);}
if(int($AZ10[$i]) != 0){$std[$i] += ($AZ10[$i] - $ave[$i])*($AZ10[$i] - $ave[$i]);}
if(int($AZ15[$i]) != 0){$std[$i] += ($AZ15[$i] - $ave[$i])*($AZ15[$i] - $ave[$i]);}
if(int($AZ20[$i]) != 0){$std[$i] += ($AZ20[$i] - $ave[$i])*($AZ20[$i] - $ave[$i]);}
if(int($AZ30[$i]) != 0){$std[$i] += ($AZ30[$i] - $ave[$i])*($AZ30[$i] - $ave[$i]);}
if(int($AZ40[$i]) != 0){$std[$i] += ($AZ40[$i] - $ave[$i])*($AZ40[$i] - $ave[$i]);}
# その行のstdを出力
if($ave_cnt[$i] <= 0){
$std[$i] = 0;
}else{
# n法 標準偏差
$std[$i] = sqrt($std[$i]/($ave_cnt[$i]));
}
}
ビットシフトサンプル
#!/usr/bin/perl
# 以下は変更する必要なし
#-----------------------------------------------------------------------------
#
# acspac2flg (version $Id: eodv,v 1.4 2007/05/22 02:22:33 Exp $)
#
# uc_acsmode_pacテレメをフラグに変換する
#
# Usage:
# > acspac2flg.pl hogehoge.csv 5 14
#
# options:
# 1.ファイル名指定
# 2.SATTIME列指定(0,1,2,3…で数える)
# 3.acspac列指定(0,1,2,3…で数える)
#
# example:
# acspac2flg.pl hogehoge.csv 5 14 #(1)
#
#-----------------------------------------------------------------------------
# Libraries
my $SATTIME;
my $acsmode;
my $subacsmode;
my $acqsts;
my $sunpre;
#-----------------------------------------------------------------------------
# Code begin
#-----------------------------------------------------------------------------
($opt) = @ARGV;
if ($opt eq "-h") {
&show_usage();
exit;
}
# オプションがない場合
if ($#ARGV == -1){
print "Error:ファイル名を指定してください\n";
}
# オプションが3つある場合
if ($#ARGV == 2){
# 対象ファイルのオープン
open(IN,"<$ARGV[0]") || die "Error: can't open $ARGV[0]\n";
@line = <IN>;
close(IN);
# ヘッダ出力
$disp = sprintf("#SATTIME,acsmode,subacsmode,acqsts,sunpre,pac\n");
print $disp;
# pacからフラグへ変換
$cnt = -1;
foreach (@line){
# ヘッダ情報を飛ばす
if ($cnt == -1){$cnt++; next;}
# 衛星時刻
$SATTIME = (split(/\,/,$_))[$ARGV[1]];
# acsmode/subacsmode
$temp = hex(((split(/\,/,$_))[$ARGV[2]]));
$acsmode = ($temp >> 0) & 0x07;
$subacsmode = ($temp >> 3) & 0x07;
$acqsts = ($temp >> 6) & 0x01;
$sunpre = ($temp >> 7) & 0x01;
# 表示
$disp = sprintf("%f,%d,%d,%d,%d,%d\n",$SATTIME,$acsmode,$subacsmode,$acqsts,$sunpre,$temp);
print $disp;
# インクリメント処理
$cnt++;
}
}
# オプションが2つある場合
if ($#ARGV == 1){
}
exit;
#-----------------------------------------------------------------------------
# Sub code begin
#-----------------------------------------------------------------------------
sub show_usage()
{
print "Usage:\n";
print "> eodv [-h]\n";
print "\n";
print "options:\n";
print " -h : 利用方法を提示する\n";
print "\n";
print "example:\n";
print "eodv -h #(1) HELP\n";
}
ASCII<->Binary変換
$ascii = pack("H*", $par1);
$bainary= unpack("H*", $par1);
文字列に文字を挿入する方法
$zip = "5770001";
substr($zip, 3, 0) = "-";
print $zip; # 577-0001
行に"#"があるとき、1ループを飛ばす
# ヘッダ情報を飛ばす
if (/#/){next;}
正規表現置換
スペースをカンマに置換する
# csv置換
$log = $_;
$log =~ s/\s+/,/g;
正規表現マッチ
先頭からyymmddmm.ssの規則でマッチする場合
if(/^[\d]{8}.[\d]{2}$/){}
2文字ずつに分割($strの文字列を2文字ずつに分割する)
my @chars = $str =~ /.{2}/g;
16進数から10進数への変換
但し、16進はCDABなどの形式であること(0xCDABはダメ
$temp_Dec = hex($temp_Hex);
16進数(文字)から数字に変換
右側の$dataが16進数文字だったものが、数字に変換される
$data = unpack("W",pack('C',hex($data)));
10進数から2進数への変換
$bins[$i] = unpack('B8',pack('C',$hexs[$i]));
16進数(文字)から実数(IEEE754 単精度float)への変換
$posx_f = unpack "f", pack "L", hex($posx);
16進数(文字)から実数(IEEE754 倍精度double)への変換
1行置換
perl -pi -e "s/txt/text/g" *.html *.pl
perl -pi -e "s/\015\012/\015/g" *.txt
参照置換
()の中身が$1になる。この場合、test,に置換される。
s/(test)/$1,/g
繰り返し置換
s/([A-F\d]{4})/$1,/g;
SHIFT-JIS関連の置換
シフトJISでは、「-」や「表」の文字をperlで置換しようとするとエラーとなってしまう
そこで以下のようにするとよい($tmp1にシフトJISの文字が来る)
$disp =~ s/\Q$tmp1\E/$tmp2/gi;
区切り切り出し
ドット「.」区切りの最初の文字列をfilenameに代入
$filename = (split(/\./,$ARGV[0]))[0];
文字列操作
$tempの0文字目から2文字を代入
$bnum = substr($temp,0,2);
perlにおける2次元配列
my @dat = ();
$data[0][0] = 1;
数字判定
整数のみであれば下記 $aを適切な変数名に変更すること
if($a =~ /^[0-9]+$/){}
実数であれば
if($a =~ /^[0-9.\-]+$/){}
テキスト出力整形
空白で列を揃えたい場合
$tmp = sprintf("%15.14s",$prv[$i]);
system関数(複数ファイルの結合)
引数が2つ以上ある場合は、下記のように指定する必要があるので、注意。
ただsystemは絶対パス指定での実行可能なので、パスが通ってなければsystemが良い。
my @cmd = ('copy' , "$tmp*_1Hz.txt",$tmp."_1Hz.tsf");
my $ret = system(@cmd);
もう1つのやり方として、
my $cmd = "cat $str1";
my $ret = `$cmd`;
2つのファイルの結合
my @cmd = ('type' , $header ,$tmp."_1Hz.txt",">".$tmp."_1Hz.tsf");
$ret = system(@cmd);
reverse関数
reverse関数は、文字列を逆順に並びかえる。
この時、スカラーかリストかにより動作がかわる。
スカラー変数:文字を逆順に並びかえる。
リスト:要素を逆順に並びかえる。
@data = reverse @data;
perlスクリプトのテンプレ
#!/usr/bin/perl
# 以下は変更する必要なし
#-----------------------------------------------------------------------------
#
# csv2srs (version $Id: eodv,v 1.4 2007/05/22 02:22:33 Exp $)
#
# SRSの算出
#
# Usage:
# > csv2srs.pl hogehoge.csv
#
# options:
# 特に無し
#
# example:
# csv2srs.pl hogehoge.csv #(1)
#
#-----------------------------------------------------------------------------
# Libraries
my @dt, @dg, @alpa, @beta, @A, @B, @C, @D, @yy;
my $tt,$bs,$bb,$ymax;
$Q = 10;
$PI = 3.1415926;
$g = 9.80665; # [m/s2]
#-----------------------------------------------------------------------------
# Code begin
#-----------------------------------------------------------------------------
($opt) = @ARGV;
if ($opt eq "-h") {
&show_usage();
exit;
}
# オプションがない場合
if ($#ARGV == -1){
print "Error:ファイル名を指定してください\n";
}
# オプションが1つある場合
if ($#ARGV == 0){
# 対象ファイルのオープン
open(IN,"<$ARGV[0]") || die "Error: can't open $ARGV[0]\n";
@line = <IN>;
close(IN);
# SRS算出
$cnt = -1;
foreach (@line){
# ヘッダ情報を飛ばす
if ($cnt == -1){$cnt++; next;}
# 時間[sec]/加速度取得[m/s2]
$dt[$cnt+1] = (split(/\,/,$_))[0];
$dg[$cnt+1] = (split(/\,/,$_))[1];
# インクリメント処理
$cnt++;
}
# ヘッダ出力
$disp = sprintf("f[Hz],G[g],Q=%f\n",$Q);
print $disp;
}
# オプションが2つある場合
if ($#ARGV == 1){
}
exit;
#-----------------------------------------------------------------------------
# Sub code begin
#-----------------------------------------------------------------------------
sub show_usage()
{
print "Usage:\n";
print "> eodv [-h]\n";
print "\n";
print "options:\n";
print " -h : 利用方法を提示する\n";
print " -make : Level-2を更新する\n";
print "\n";
print "example:\n";
print "eodv -h #(1) HELP\n";
}
perlスクリプトのexe化
perlスクリプトをexe化する方法がある。exe化する理由としては、perl実行環境がない人への配布等、perlが分からない人にあげても当然実行も加工もできないので、exe化してアプリケーションとして配布すると便利である。
exe化にはいくつか方法がある。perl2exeは簡単に変換環境を整えることができるが、フリーではないことと、ファイル読み込み(おそらくパスの指定)でエラーが出る(原因がよくわからない)。個人的にはPARがオススメ。ただし、PARは環境を整えるのが大変である。
perl2exe
PAR
perl2exeのバージョンアップにより、パス問題が解決されているもよう?簡単にplをexe化でき、ほぼ想定通りに動かすことができた。PARの環境を整えるより簡単なので、良いかも…。
使い方は、コマンドプロンプト上で、「perl2exe.exe hoge.pl」でOK
組込み用のモジュールを使用している場合は、上手く変換できない場合がある。
32bit:p2x-9.100-Win32
perl2exeで変換できる(できている?)モジュール
- use Time::Local;
- use File::Basename;
最終更新:2018年06月13日 19:36