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

■ナビゲータ

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

  1. [Windows版Rubyの細道・けもの道]
    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. [スクリプトと入力データのサンプル]
Perlではどう処理する?
同じことをPerlではこうしています。

3.応用編

3-3.ファイルの統合

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

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

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

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

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

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

【スクリプト】
# coding:utf-8  
# change_all.rb 
# 内容 : フォルダ内のファイルについてすべて同一の変更を行う    
# Copyright (c) 2012-2015 Mitsuo Minagawa, All rights reserved. 
# (minagawa@fb3.so-net.ne.jp)   
# 使用方法 : c:\>perl change_all.rb 
#   

require 'nkf'   

# 入力ファイル  
in1_file    =   open("filename.txt","r")    

w_data  =   Array.new() 
# 正規表現パターンにマッチするデータが存在するかどうかをチェックするフラグ  
w_change    =   nil 

# 主処理    
while   (filename   =   in1_file.gets)      
    filename.chomp! 
# ファイル名をもとに全データを読み込む  
    w_data  =   IO.readlines(filename)  

    i   =   0   
    while   (i  <   w_data.size)    
# 正規表現パターンにマッチするデータが存在するかどうかをチェックする    
        line1   =   w_data[i]   
        line1   =   NKF::nkf( '-Swm0', line1)   
#       if      (/3-5.文字コード変換/   =~  line1)  
        if      ((/HTML 4.01 Transitional/  =~  line1)  ||  
                (/<html lang="ja">/         =~  line1)) 
                w_change    =   "xxx"   
        end 

# 正規表現パターンにマッチするデータが存在したら、置き換える    
#       line1.gsub!(/3-5.文字コード変換/,"3-5.文字コードの変換")    
        line1.gsub!(/HTML 4.01 Transitional/,'HTML 4.0 Transitional')   
        line1.gsub!(/<html lang="ja">/,'<html>')    

        w_data[i]   =   NKF::nkf( '-Wsm0', line1)   
        i   +=  1   
    end 

# マッチした場合のみ出力する    
    if      (w_change   ==  "xxx")  
# 読み込んだファイルを出力ファイルとして、openし直す    
            out1_file   =   open(filename,"w")  
# 変更した内容を出力する    
            w_data.each     {|line1|        
                    out1_file.print line1   
            }   
    end 
# 正規表現パターンにマッチするかどうかをチェックするフラグを初期化する  
    w_change    =   nil 

end 

# ファイルのクローズ    
in1_file.close  
   
【スクリプトとデータのサンプル】

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

【スクリプトの解説】

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

初期値設定

# coding:utf-8  
# change_all.rb 
# 内容 : フォルダ内のファイルについてすべて同一の変更を行う    
# Copyright (c) 2012-2015 Mitsuo Minagawa, All rights reserved. 
# (minagawa@fb3.so-net.ne.jp)   
# 使用方法 : c:\>perl change_all.rb 
#   

require 'nkf'   

# 入力ファイル  
in1_file    =   open("filename.txt","r")    

w_data  =   Array.new() 
# 正規表現パターンにマッチするデータが存在するかどうかをチェックするフラグ  
w_change    =   nil 
   

上記スクリプトでは、変更するテキストファイルを"shift_jis"としています。Rubyでは、いわゆる全角文字やダブルクォーテーション(")などの半角文字は正規表現のパターンマッチを行うとエラーになりますので、ここでは、"shift_jis"を"utf-8"に変換してパターンマッチを行っています。これにともない、スクリプトも"utf-8"で記述します。このため、スクリプトの1行目にマジックコメントである"# coding:utf-8"をしていしています。

つぎに"shift_jis"を"utf-8"に変換するために"nkfライブラリ"を使用しますので、"require 'nkf' "を指定します。"nkfライブラリ"についての説明は[3-5-2.文字コードの変換(nkfライブラリ利用)]を参照してください。

"w_data"は1つのテキストファイル全体を入れておく配列です。1行を1つの要素とします。また、"w_change"は該当する正規表現が存在したかどうかをチェックするフラグです。このフラグによって、同じフォルダの中にあっても、正規表現にパータンマッチしなかったテキストファイルは変更しませんし、タイムスタンプも変更しなくなります。

ファイルの読み込み

in1_file    =   open("filename.txt","r")    

while   (filename   =   in1_file.gets)      
    filename.chomp! 
# ファイル名をもとに全データを読み込む  
    w_data  =   IO.readlines(filename)  
   

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

「w_data = IO.readlines(filename)」のようにreadlineメソッドを使用することで、filenameに関連づけられたデータをすべて読み込んで、左辺の配列に入れます。

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

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

    i   =   0   
    while   (i  <   w_data.size)    
# 正規表現パターンにマッチするデータが存在するかどうかをチェックする    
        line1   =   w_data[i]   
        line1   =   NKF::nkf( '-Swm0', line1)   
#       if      (/3-5.文字コード変換/   =~  line1)  
        if      ((/HTML 4.01 Transitional/  =~  line1)  ||  
                (/<html lang="ja">/         =~  line1)) 
                w_change    =   "xxx"   
        end 
   

配列(ここではw_data)にセットしたデータを1行ずつチェックして、正規表現で指定したパターンが存在しているかどうかチェックしていきます。正規表現でどのような指定ができるかについては、[2-5.パターンマッチ処理]を参照してください。"nkfライブラリ"で文字コードを"utf-8"に変更することによって、いわゆる全角文字列などのパターンマッチでエラーになってしまう文字列でもパターンマッチが実行できるようになります。

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

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


# 正規表現パターンにマッチするデータが存在したら、置き換える    
#       line1.gsub!(/3-5.文字コード変換/,"3-5.文字コードの変換")    
        line1.gsub!(/HTML 4.01 Transitional/,'HTML 4.0 Transitional')   
        line1.gsub!(/<html lang="ja">/,'<html>')    

        w_data[i]   =   NKF::nkf( '-Wsm0', line1)   
        i   +=  1   
    end 
   

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

正規表現に該当する文字列を最初に見つかったものだけにしたい場合はsub!メソッド、正規表現に該当するものをすべて変更する場合は、gsub!にします。また、正規表現の中で"/"を使う場合は、正規表現の"/"は"\/"と変更します。

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

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

# マッチした場合のみ出力する    
    if      (w_change   ==  "xxx")  
# 読み込んだファイルを出力ファイルとして、openし直す    
            out1_file   =   open(filename,"w")  
# 変更した内容を出力する    
            w_data.each     {|line1|        
                    out1_file.print line1   
            }   
    end 
# 正規表現パターンにマッチするかどうかをチェックするフラグを初期化する  
    w_change    =   nil 
   

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




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