perl

ファイル名生成(拡張子だけ変更)

$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