■Windows版Perlの細道・けもの道

■ナビゲータ

[南北館(最初のメニュー)]

  1. [Windows版Perlの細道・けもの道]
    1. [1.準備編]
    2. [2.基本編]
    3. [3.応用編]
      1. [3-1.固定長データとCSVデータとの変換]
      2. [3-2.重複データの処理]
      3. [3-3.フォルダ内の一括処理]
        1. [3-3-1.フォルダ内のファイル名を出力する]
        2. [3-3-2.フォルダ内の複数のファイルをまとめて、1つのファイルに出力する]
        3. [3-3-3.フォルダ内のファイルについて一括変更をする]
      4. [3-4.1つのファイルを複数のファイルに分割する]
      5. [3-5.文字コードの変換]
      6. [3-6.半角全角変換]
      7. [3-7.多次元配列の処理]
      8. [3-9.その他]
    4. [スクリプトと入力データのサンプル]
rubyではどう処理する?
同じことをrubyではこうしています。

3.応用編

3-3.フォルダ内の一括処理

3-3-3.フォルダ内のファイルについて一括変更をする

[3-3-1.フォルダ内のファイル名を出力する]で出力したフォルダのファイル名を読み込んで、[2-5.パターンマッチ処理]を行い、複数のファイルを一括更新する処理です。1つ1つのファイルを開いて、[検索]-[置換]を行う必要がないため、効率よく、ファイルを修正することができます。

まず、[3-3-1.フォルダ内のファイル名を出力する]で出力した"filename.txt"にあるファイル名を読み込んで、そのファイルの中で該当する正規表現があるかどうかをチェックし、その後、正規表現に該当する文字列があれば、置き換えていきます。最後に該当する正規表現がある場合のみ、変更した内容を出力していきます。したがって、該当する正規表現が全くない場合は、出力されませんので、内容も変更されませんし、タイムスタンプもそのままの状態になります。

"filename.txt"の内容を事前に修正しておくことによって、フォルダ内のすべてのファイルではなく、一部のファイルだけを対象にすることができます。

なお、スクリプトの作り方によっては、入力ファイルを間違えて修正してしまう範囲が大きくなることがありますので、事前にバックアップを取った上で実行することをお勧めします。これにより、最悪の場合でも入力ファイルを修正前の状態に戻すことができます。

実際に応用する場合は、入出力データのファイル名等を変更して利用します。

【スクリプト】
# change_all.pl 
# 内容 : フォルダ内のファイルについてすべて同一の変更を行う    
# Copyright (c) 2012 Mitsuo Minagawa, All rights reserved.  
# (minagawa@fb3.so-net.ne.jp)   
# 使用方法 : c:\>perl change_all.pl 
#   
use open ":encoding(cp932)";    #入出力ファイルはcp932(shift_jis)
use utf8;                       #スクリプトはutf-8として指定する

# 正規表現パターンにマッチするデータが存在するかどうかをチェックするフラグ  
$w_change   =   undef;  

open(IN1,"filename.txt");       
while   ($filename  =   <IN1>)  {       
    chomp($filename);       
    open(IN2,"$filename");      
# ファイル名をもとに全データを読み込む  
    @data   =   <IN2>;      

    foreach $line   (@data) {   
# 正規表現パターンにマッチするデータが存在するかどうかをチェックする    
#       if      (($line     =~  /HTML 4.0 Transitional/)    
#           or  ($line      =~  /<html>/))                  {
        if      ($line      =~  /3-7.多次元データの処理/)         {
                $w_change   =   "xxx";  
        }   
    }       

# 正規表現パターンにマッチするデータが存在したら、置き換える    
#   foreach $line   (0..$#data) {   
    foreach $line   (@data) {   
#       $line   =~  s*HTML 4.0 Transitional*HTML 4.01 Transitional*g;   
#       $line   =~  s*<html>*<html lang="ja">*g;    
#       $line   =~  s*<p><li>*<li><p>*g;    
#       $line   =~  s*</li></p>*</p></li>*g;    
#       $line   =~  s/<\/li><\/p>/<\/p><\/li>/g;    
#       $line   =~  s*<font class*<strong class*g;  
#       $line   =~  s*</font>*</strong>*g;  
        $line   =~  s/3-7.多次元データの処理/3-7.多次元配列の処理/g;
        $line   =~  s/3-7-1.多次元データの処理/3-7-1.多次元配列の処理/g;
    }       

# マッチした場合のみ出力する    
    if      ($w_change  eq  "xxx")          {   
            $output =   $filename;  
# 読み込んだファイルを出力ファイルとして、openし直す    
            open(OUT1,">$output");      
# 変更した内容を出力する    
            foreach $line   (@data)     {   
                print   OUT1    $line;  
            }   
    }   
# 正規表現パターンにマッチするかどうかをチェックするフラグを初期化する  
    $w_change   =   undef;  
}       
close(IN1);     
close(IN2);     
    
【スクリプトとデータのサンプル】

スクリプトはこちらにあります(必ずutf8で保存してください)。

【スクリプトの解説】

それでは、1つずつ解説していきましょう。

初期値の設定

use open ":encoding(cp932)";    #入出力ファイルはcp932(shift_jis)
use utf8;                       #スクリプトはutf-8として指定する

# 正規表現パターンにマッチするデータが存在するかどうかをチェックするフラグ  
$w_change   =   undef;  
   

上記の例では、入出力ファイルが"shift_jis"ですので、[3-5-3.文字コードの変換(open プラグマ 使用)]で解説するopenプラグマを使用して、入出力ファイルをuse open ":encoding(cp932)";としてファイルをオープンするように指定します。入出力ファイルが"UTF-8"の場合は、use open ":encoding(utf-8)";、入出力ファイルが"euc-jp"の場合は、use open ":encoding(euc-jp)";とします。

これに対し、スクリプトの中で全角文字を使用する場合は、"shift_jis"ではエラーになってしまうため、"UTF-8"で保存しておきますので、"use utf8;"と指定します。

また、$w_changeは正規表現パターンにマッチするデータが存在するかどうかをチェックするためのフラグです。

ファイルの読み込み

    open(IN1,"filename.txt");
    while   ($filename  =   <IN1>)  {
        chomp($filename);
        open(IN2,"$filename");
    # ファイル名をもとに全データを読み込む
        @data   =   <IN2>;      
   

[3-3-1.フォルダ内のファイル名を出力する]で出力した"filename.txt"を読み込みます。"filename.txt"を事前に変更しておくことで置換処理の対象にしたいファイルだけに絞り込んでおくことができます。特にテキストファイル以外のファイルがある場合は、該当するファイル名を削除しておく必要があります。

「@data = <IN2>;」のように左辺に配列、右辺にファイルハンドルを指定すると、ファイルハンドルに関連づけられたデータをすべて読み込んで、左辺の配列に入れます。

ただし、フォルダ名やファイル名に全角文字が含まれていると、正常にファイルをopenすることができませんので、注意してください(全角文字がフォルダ名やファイル名に含まれている場合は、ドライブ名から指定する絶対的なパスではなく、相対的なパスに変更して、フォルダ名に全角文字が入らないようにしたり、フォルダ名やファイル名を変更しておく必要があります。相対的なパスについてはこちらを参照してください。)。

正規表現パターンにマッチするかどうかチェックする

    foreach $line   (@data) {   
# 正規表現パターンにマッチするデータが存在するかどうかをチェックする    
#       if      (($line     =~  /HTML 4.0 Transitional/)    
#           or  ($line      =~  /<html>/))                  {
        if      ($line      =~  /3-7.多次元データの処理/)         {
                $w_change   =   "xxx";  
        }   
    }       
   

配列(ここでは@data)にセットしたデータを1行ずつチェックして、正規表現で指定したパターンが存在しているかどうかチェックしていきます。正規表現でどのような指定ができるかについては、[2-5.パターンマッチ処理]を参照してください。パターンマッチでエラーになってしまうものの1つにカタカナの長音「ー」がありますが、openプラグマを指定することでエラーを回避できます。

上記の例では条件は2つしかありませんが、必要に応じて加減してください。「$w_change = "xxx";」は正規表現で指定したパターンのないファイルについては、あとでファイルに出力しないようにするためのフラグです。

正規表現パターンに該当したら、置き換える

# 正規表現パターンにマッチするデータが存在したら、置き換える    
#   foreach $line   (0..$#data) {   
    foreach $line   (@data) {   
#       $line   =~  s*HTML 4.0 Transitional*HTML 4.01 Transitional*g;   
#       $line   =~  s*<html>*<html lang="ja">*g;    
#       $line   =~  s*<p><li>*<li><p>*g;    
#       $line   =~  s*</li></p>*</p></li>*g;    
#       $line   =~  s/<\/li><\/p>/<\/p><\/li>/g;    
#       $line   =~  s*<font class*<strong class*g;  
#       $line   =~  s*</font>*</strong>*g;  
        $line   =~  s/3-7.多次元データの処理/3-7.多次元配列の処理/g;
        $line   =~  s/3-7-1.多次元データの処理/3-7-1.多次元配列の処理/g;
    }       
   

ここで実際に正規表現のパターンに該当したら、置き換え処理を行っていきます。

区切り文字は通常、"/"ですが、上記のように"*"などの文字を使用することができます。使用できる文字は英数字と"_"(アンダーバー)以外の文字ですが、具体的には、"!"、"#"、"$"、"%"、"&"、"*"などを使用することができます。

ただし、"("と")"、"<"と">"、"{"と"}"、"["と"]"は必ず対応させて使用します。たとえば、"s*</font>*</strong>*g;"s{</font>}[</strong>]g;のように指定することができます。また、区切り文字として"/"を使い、さらに正規表現の中で"/"を使う場合は、正規表現の"/"は"\/"と変更します。

その他の正規表現でどのような指定ができるかについては、[2-5.パターンマッチ処理]を参照してください。

変更したものだけを出力する

# マッチした場合のみ出力する    
    if      ($w_change  eq  "xxx")          {   
            $output =   $filename;  
# 読み込んだファイルを出力ファイルとして、openし直す    
            open(OUT1,">$output");      
# 変更した内容を出力する    
            foreach $line   (@data)     {   
                print   OUT1    $line;  
            }   
    }   
# 正規表現パターンにマッチするかどうかをチェックするフラグを初期化する  
    $w_change   =   undef;  
   

最後に変更したものだけを出力していきます。$w_changeの値によって、正規表現で置換処理を行ったかどうかを判断し、置換処理を行ったファイルだけを出力します。これにより、変更していないファイルについては変更されませんし、タイムスタンプも変更されません。最後に$w_changeの値を初期化します。




Copyright (c) 2012-2013 Mitsuo Minagawa, All rights reserved.