ゴミ溜め@技術系日常系雑文

主にWeb技術やそのほかつまづいたこととか引っかかって調べたこととかをまとめてます。

はてなダイアリーから引っ越しました。)

右クリックで選択したファイルを一括して新しいフォルダに移動するバッチ書いた

複数のファイルを同じフォルダに格納したいんだけど、いちいち新規フォルダ作成→ファイルを選択→ドラッグ&ドロップって言う操作が面倒なので、複数のファイルを選択して、右クリック(コンテキスト)メニューから一括で出来るようにした。

続きを読む

Excel マクロ(VBA) でシートを名前順でソートする

備忘録としてVBAマクロを掲載していくシリーズ。

シートをシート名昇順にソートするマクロ。
Excel マクロ(VBA) でシート一覧を作成の応用。

Sub シートをソート()

    ' 画面更新を一時的に無効化する。
    Application.ScreenUpdating = False
        
    Dim cnt As Long
    cnt = Sheets.count
    
    ' 作業用シートをブック先頭に作成
    Dim work As Worksheet
    Set work = Worksheets.Add(Sheets(1))
    
    ' シート名一覧を作成する処理
    Dim i As Long
    For i = 1 To cnt
        work.Cells(i, 1) = Sheets(i).Name
    Next i
    
    ' 一覧をExcel標準機能でソート
    work.Range("A1:A" & i).Sort Key1:=Range("A1"), _
                       Order1:=xlAscending, _
                       Header:=xlGuess

    ' 一覧の順番通りにシートを並べ替える
    For i = 1 To cnt
        Sheets(work.Cells(i, 1).Value).Move before:=work
    Next i
    
    ' シート削除時の警告表示を停止
    Application.DisplayAlerts = False
        
    ' 作業用シートを削除
    work.Delete
    
    ' 警告表示を再開する
    Application.DisplayAlerts = False
    
    ' 画面更新を再開する
    Application.ScreenUpdating = True
        
End Sub

Excel マクロ(VBA) でブック内の画像をすべて取り除く

備忘録としてVBAマクロを掲載していくシリーズ。

ブック内に大量に画像が張り付けてあって、それをすべて消す作業が発生したので、めんどくさくなったので下記のマクロにて処理。

まず、アクティブなシート内の画像を全て消す処理は、下記。

ActiveWorksheet.Pictures.Delete

これをForループで全シートに対して順次行ってあげるだけ。

Sub 画像をすべて取り除く()
     Dim sht As Variant

     For Each sht In Sheets
          sht.Pictures.Delete
     Next sht
End Sub

Excel マクロ(VBA) で対象セルに画像を張り付ける

備忘録としてVBAマクロを掲載していくシリーズ。

指定したセル上に、セルに寸法を合わせた画像を貼り付ける処理。
指定したセルが結合されたセルの場合、結合したセル全体のサイズに合わせる。


まずコア部分。

引数は下記の通り。
tgtRange : 貼り付ける先のセル(結合セルの場合は左上のセルを指定。)
fname : 貼り付ける画像のパス(省略した場合は、対象のセルに記入されたパスを参照する)

Function 対象セルに画像を張り付ける(ByRef tgtRange, Optional fname As String)

     If fname = "" Then
          If tgtRange.Text = "" Then Exit Function
          fname = Replace(ActiveWorkbook.FullName, _
                      ActiveWorkbook.Name, "") & tgtRange.Text
     End If

     ' 貼り付け位置・サイズの調整
     ' ( Width, Heightの指定が必須のため、仮の値を設定 )
     Dim objShape
     Set objShape = tgtRange.Parent.Shapes.AddPicture( _
          Filename:=fname, _
          LinkToFile:=False, _
          SaveWithDocument:=True, _
          Left:=tgtRange.Left + 1, _
          Top:=tgtRange.Top + 1, _
          Width:=tgtRange.MergeArea.Width, _
          Height:=tgtRange.MergeArea.Height)
     With objShape
          .ScaleHeight 1, msoTrue
          .ScaleWidth 1, msoTrue
          '.LockAspectRatio = msoTrue '縦横費を固定。
          .Width = tgtRange.MergeArea.Width
          .Height = tgtRange.MergeArea.Height
     End With

End Function


現在アクティブなセルに対して、画像選択ダイアログを開いて貼り付けるには、下記の関数を追加する。「Ctrl+Shift+V」とかショートカットを設定しておくと一発起動できて便利。

Sub 写真貼り付け()

'
' 写真貼り付け Macro
'
' Keyboard Shortcut: Ctrl+Shift+V

     Dim t As Range
     Set t = ActiveCell

     Dim fname As String
     fname = Application.GetOpenFilename ' ファイル選択ダイアログを開く。

     If fname = "False" Then fname = ""
          ' ※ GetOpenFilename は、ファイルが選択されなかった時には、
          '    文字列"False"を返す。

     Call 対象セルに画像を張り付ける(t, fname)

End Sub

Excel マクロ(VBA) でシート一覧を作成

備忘録としてVBAマクロを掲載していくシリーズ。

いまあるシート名一覧を出力する方法。
ブックの末尾に新たにシートを追加して、そこに現在あるシート名一覧を出力する。

Sub シート一覧を作成()
    Dim cnt as Long
    cnt = Sheets.Count

    Dim work As Worksheet
    Set work = Worksheets.Add(, Sheets(cnt))

    Dim i As Long
    For i = 1 To cnt
            work.Cells(i, 1) = Sheets(i).Name
    Next i
End Sub

PT3導入したので、EpgTimerで録画したファイル名を書き換えるバッチ+perlスクリプトを書いた

発売日に買ったのにずっと放置してたPT3をようやくPCに導入した。
で、EpgTimerで録画したTSファイルの録画情報ファイル(.ts.program.txt)からサブタイトルを抽出してTSファイルのファイル名に追記したいと思ったので、PerlとBATで何とかしてみた。

で、今回作ったプログラムの動作は、録画情報ファイルをrename.batにドラッグアンドドロップすることで動作するようにした。

Perlを選んだ理由は「何となく」。
最近使ってないのでちょっと使ってみたくなったので使っただけなので、特に意味は無い。

フォルダ構成

EpgTimer側で動画保存先を「D:\TV_RECORDING」としておく。
動画保存先フォルダに下記のような構成でファイルを作成する。

動画保存先(D:\TV_RECORDING\)
 └ rename\
  ├ rename.bat
  └ rename.pl

このうちrename.batに録画情報ファイル(.ts.program.txt)をドラッグ&ドロップすると、rename.plを呼び出し、ファイル名書き換え処理を行う流れ。

EpgTimerの設定

「設定」→「動作設定」→「予約情報管理」から、「録画時のファイル名にPlugInを使用する」にチェックを入れ、下記の通り「設定」する。

$Title2$($SDYYYY$-$SDMM$-$SDDD$-$STHH$-$STMM$).ts
(番組名(放送日時ハイフン区切り).ts)

構文がよくわからない。どこかにまとまってないかな。

なお今回は番組名と放送日時の間にサブタイトルを挿入するスクリプトをつくる。

ソース

rename.bat

@echo off
setlocal ENABLEDELAYEDEXPANSION

for %%i in (%*) do (
perl %~dp0rename.pl %%i
)

「%*」は与えられた引数をすべて返すもの。EpgTimerの吐くファイル名は、モノによっては全角・半角スペースを含むモノが有り、%1だと通らないことがあるので注意。

[2014/04/05 加筆]複数のパスが渡されたときにパス毎にrename.plを呼び出すように改良。

次にrename.pl

use Config::Tiny;

# SETTINGS ##############################################################
# ファイルの拡張子
my %exp = (
	"ts"      => ".ts",
	"program" => ".ts.program.txt",
	"err"     => ".ts.err"
);

# 設定ファイルのパス
my $ini = Config::Tiny->read('D:\TV_RECORDING\rename\settings.ini');

# ConvertText.txt ファイルのパス
my $convfile = "C:\\Users\\Tatsuya\\app\\EpgDataCap_Bon\\x64\\ConvertText.txt";

# 使用禁止文字
my %replacechars = (
	':'  => ':',
	';'  => ';',
	'/'  => '/',
	'\\' => '¥', 
	'|'  => '|',
	','  => ',',
	'*'  => '*',
	'?'  => '?',
	'"'  => '”',
	'<'  => '<',
	'>'  => '>'
);
#########################################################################

my $routine = "";

print "-------------------------------------------------\n";

# バッチからファイルパスを受け取る。
my $arg = shift; &message("arg : $arg\n");
my %fpath = ("ts"=>"", "err" => "", "program"=>"");

if(!$arg) { &error("ファイルが指定されていません"); }

$arg =~ s/\.ts\.err$//;

$fpath{ts} = $arg.$exp{ts};
&message("[動画ファイルパス]\n$fpath{ts} ...");
-f $fpath{ts} ? &message("OK\n") : &error("ファイルがありません");

$fpath{err} = $arg.$exp{err};
&message("[エラーログファイルパス]\n$fpath{err} ...");
-f $fpath{err} ? &message("OK\n") : &error("ファイルがありません");

$fpath{program} = $arg.$exp{program};
&message("[動画情報ファイル]\n$fpath{program} ...");
-f $fpath{program} ? &message("OK\n") : &error("ファイルがありません");

&message("\n");

my @fpath = split(/\\/, $arg);

# ファイル名を取得。
$fname = @fpath[$#fpath];
&message("ファイル名      : $fname($exp{ts}|$exp{program}|$exp{err})\n");

# ファイルのあるディレクトリのパスを取得。
@fdir = @fpath;
pop @fdir;
$fdir = join("\\", @fdir) . "\\";
&message("ファイル保存場所: $fdir\n");

$fname =~ /^(.*)(\(\d{4}-\d{2}-\d{2}-\d{2}-\d{2}\))$/;
$before = $fname;
my ($title, $time) = ($1, $2);
&message("録画開始時刻    : $time\n");
&message("番組名          : $title\n");

&message("-------------------------------------------------\n");
&rename(%fpath);
RENAME_END:;
_END:;


sub rename {

	my %fpath = @_;

	&message("# リネーム処理開始...\n");

	$routine = "RENAME";

	# 動画情報ファイルを開く。
	open(FH, "< " . $fpath{program}) or &error(
		"動画情報ファイルの展開に失敗しました。\n" .
		"(指定されたパス: $fpath{base})");
	
	# サブタイトルの抽出。
	my $subtitle;
	while(my $line = <FH>) { print "[line]$line\n";
		chomp($line);
		if($title eq "Z/X IGNITION" && $line =~ /PHASE([0-90-9]+)/i) {
			$subtitle = "#$1";
			$subtitle =~ s/^(.*)』$/$1/; # なぜかカッコがついてきてしまうので削除。
			last;
		} elsif($line =~ /^(#|#|第)[0-90-9]+/i) {
			$subtitle = $line; last;
		}
	}

	# 使用禁止文字の置換
	while(my ($b, $a) = each(%replacechars)) {
		$subtitle =~ s/\Q$b\E/$a/g;
	}
	
	print "[subtitle]$subtitle\n";
	$subtitle ? &message("サブタイトル    : $subtitle\n")
	          : &error("サブタイトルらしき文字列は見当たりませんでした。");
	close(FH);

	if( $ini->{'command'}->{'rename_enable_yes'} ? 1 : &command("上記の内容でリネームしますか?" )) {

		&message("リネームします。\n");
		
		# リネーム実行
		my $rename = "$title$subtitle$time";
		while( ($step, $e) = each(%exp) ) {
			my $before = "$fdir$before$e";
			my $after = "$fdir$rename$e";
			
			&message("[$step] $before ...\n... $after\n");
			rename($before, $after) or &error("リネームエラー($e :$!)");
		}

		$before = $rename;

	} else {
		&message("リネームをキャンセルしました。\n");
	}

	&message("# リネーム処理終了...\n");
	&message("-------------------------------------------------\n");
}

sub command {
	&message(shift."(Y/N) ");
	my $in = <STDIN>;
	chomp $in;
	return ($in eq "y" || $in eq "Y" || $in eq "") ? 1 : 0;
}

sub message {
#	print encode("cp932", shift);
	print shift;
}

sub error {
	my $msg = shift;
	&message("[!]$msg\n");
	
	my $in = <STDIN>;

	goto $routine."_END";
}

[2014/04/05 追記]ソースを一新した。とりあえず動いてるけど文字コードの関係でたまに文字化けするので改良予定。

以上。