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

■ナビゲータ

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

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

3.応用編

3-5.文字コードの変換

3-5-3.文字コードの変換(open プラグマ 使用)

<open プラグマ>を利用して、入力ファイルの文字コードを変更する方法です。入力ファイルの文字コード、出力ファイルの文字コードのそれぞれを一括して指定する方法です。また、入出力ファイルをすべて同じ文字コードとして指定することもできます。

<open プラグマ>は特に全角文字を含むパターンマッチを行う場合に必要となるものです。パターンマッチ処理については、[2-5.パターンマッチ処理]を参照してください。また、具体的に全角文字を含むパターンマッチ処理の例は[3-3-3.フォルダ内のファイルについて一括変更をする]に挙げてあります。こうしたパターンマッチを行う場合、入出力ファイルの文字コードの指定は<open プラグマ>で行い、スクリプトの文字コードの指定は<utf8モジュール>か<encodingモジュール>で行います。なお、<encodingモジュール>を使用すると、「$出力」のような全角文字を使った変数を使うこともできます。

下記の例では単純な1件ごとの入出力を行うスクリプトですが、実際に利用するには、スクリプトを実際に利用するものに変更するとともに、入力ファイルや出力ファイルのファイル名と文字コードを変更します。

【スクリプト】
# open_pragma.pl
# 内容 : openプラグマによって、文字コードの変換を行う
# Copyright (c) 2011 Mitsuo Minagawa, All rights reserved.
# (minagawa@fb3.so-net.ne.jp)
# 使用方法 : c:\>open_pragma.pl
#

use open IN  => ":encoding(utf8)";
use open OUT => ":encoding(windows-31j)";

open(IN1, "input_utf8.txt");
open(OUT1, ">output.txt");

while    ($line1    =    <IN1>)    {
    chomp($line1);

# CSV形式の $line1 から値を取り出して @in1 に入れる

    my $tmp =   $line1;
    $tmp    =~  s/(?:\x0D\x0A|[\x0D\x0A])?$/,/;
    @in1    =   map {/^"(.*)"$/ ? scalar($_ = $1, s/""/"/g, $_) : $_}
                ($tmp =~ /("[^"]*(?:""[^"]*)*"|[^,]*),/g);

    $out1   =   join("\t",@in1);
    print    OUT1    "$out1\n";
}

close(IN1);
close(OUT1);
    
【スクリプトとデータのサンプル】

スクリプトはこちらにあります。

【スクリプトの解説】

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

use open IN  => ":encoding(utf8)";
use open OUT => ":encoding(windows-31j)";
use open IO  => ":encoding(shift_jis)"; 
use open ":encoding(shift_jis)";
   

入力ファイルの文字コードを指定する場合は、「use open IN」で指定します。また、出力ファイルの文字コードを指定する場合は、「use open OUT」で指定します。入出力ファイルが同じ文字コードの場合は、「use open IO」で指定します。また、この場合、「use open ":encoding(shift_jis)";」のように指定することもできます。指定する文字コードについては下記の表を参照してください。

open プラグマで指定できる文字コード

文字コード 内    容
utf-8 unicodeを表す文字コードの一種。Perl5.8以降、Perlの内部では、文字列はutf8で扱われています。"utf8"と指定しても可
euc-jp 主にUNIXなどで利用されている文字コード。"eucjp"と指定しても可
shift_jis 主にWindowsで利用されている文字コード。shiftjisなどと指定しても可
cp932 主にWindowsで利用されている文字コード。shift_jisに機種依存文字を含んだもの。一般にはshift_jisと指定するよりは、こちらで指定した方が変換エラーは発生しにくくなります。windows-31jと指定しても可

また、入力ファイル用の文字コードには下記を指定することができます。

open プラグマで指定できる文字コード(入力ファイル専用)

文字コード 内    容
UTF-16BE 入力ファイルの文字コードをUTF-16(Big Endian/BOMなし)とする
UTF-16LE 入力ファイルの文字コードをUTF-16(Little Endian/BOMなし)とする。
UTF-32BE 入力ファイルの文字コードをUTF-32(Big Endian/BOMなし)とする。
UTF-32LE 入力ファイルの文字コードをUTF-32(Little Endian/BOMなし)とする。

Big Endianとは「データの上位バイトからメモリに並べる方式」のことで、Little Endianとは「データの下位バイトからメモリに並べる方式」のことです。

CPUでは、SunのSPARC、Motorolaの68K、コンピュータでは、IBM系の汎用機やMacintosh等が「ビッグエンディアン(Big Endian)」を採用しているのに対し、CPUでは、インテルのx86系、コンピュータでは、Windows等が「リトルエンディアン(Little Endian)」を採用しています。



また、文字コードがutf-8の場合に限り、下記のように指定することもできます。

use open IN  => ":utf8";
use open OUT => ":utf8";
use open IO  => ":utf8";
use open ":utf8";
   

なお、[2-5.パターンマッチ処理]などを行う場合は、さらに、下記のように<utf8モジュール>か<encodingモジュール>を利用して、正常に処理できるようにします。この場合、スクリプトを指定した文字形式にあわせて「名前をつけて保存」します。

この結果、入出力ファイルはshift_jisのままで、スクリプトをutf-8やeuc-jpに変えることで、パターンマッチ処理ができるようになります。

# open_pragma.pl
# 内容 : openプラグマによって、文字コードの変換を行う
# 2011 Minagawa Mitsuo (minagawa@fb3.so-net.ne.jp)
# 使用方法 : c:\>open_pragma.pl
#

use open IN  => ":encoding(windows-31j)";
use open OUT => ":encoding(windows-31j)";
use utf8;

open(IN1, "input_sjis.txt");
open(OUT1, ">output.txt");

while    ($line1    =    <IN1>)    {
    chomp($line1);

# CSV形式の $line1 から値を取り出して @in1 に入れる

    my $tmp =    $line1;
    $tmp    =~   s/(?:\x0D\x0A|[\x0D\x0A])?$/,/;
    @in1    =    map {/^"(.*)"$/ ? scalar($_ = $1, s/""/"/g, $_) : $_}
            ($tmp =~ /("[^"]*(?:""[^"]*)*"|[^,]*),/g);
# shift_jisのままでは「表」の文字はパターンマッチ処理を行うことができません。

    if      ($in1[2]    =~    /表/)        {
             $in1[1]    =    "XYZ";
    }

    $out1    =    join("\t",@in1);
    print    OUT1    "$out1\n";
}

close(IN1);
close(OUT1);
    

encodingモジュールを利用する場合は、以下のようにします。

# open_pragma.pl
# 内容 : openプラグマによって、文字コードの変換を行う
# 2011 Minagawa Mitsuo (minagawa@fb3.so-net.ne.jp)
# 使用方法 : c:\>open_pragma.pl

use open IN  => ":encoding(windows-31j)";
use open OUT => ":encoding(windows-31j)";

# utf-8の場合は、以下のように指定します("utf-8"は"utf8"としても可能です)。
use encoding 'utf-8';
# euc-jpの場合は、以下のように指定します。
use encoding 'euc-jp';

open(IN1, "input_sjis.txt");
open(OUT1, ">output.txt");
    

また、encodingモジュールは「Filter => 1」をつけると、「$出力」等と変数に漢字などの全角文字を指定することができるようになります(半角文字との混在も可能です)。

# perl_layer.pl
# 内容 : shift_jis形式のデータを読み込んでutf-8で出力する 
# 2011 Minagawa Mitsuo (minagawa@fb3.so-net.ne.jp)
# 使用方法 : c:\>perl_layer.pl

# utf-8の場合は、以下のように指定します("utf-8"は"utf8"としても可能です)。
use encoding 'utf-8', Filter => 1;
# euc-jpの場合は、以下のように指定します。
use encoding 'euc-jp', Filter => 1;

open(IN1, "input_sjis.txt");
open(OUT1, ">output.txt");
・・・・・

	$出力1	=	join("\t",@in1);
	print	OUT1	"$出力1\n";

    



その他注意すべきこと

フォルダ内の複数のファイルについて一括して文字コードを変換する場合は、[3-3-1.フォルダ内のファイル名を出力する]でフォルダ内のファイル名をファイルに出力した後、[3-3-3.フォルダ内のファイルについて一括変更をする]と上記のスクリプトを参照して、スクリプトを作成します。

ここでは、"filename.txt"には文字コードがshift_jisになっている拡張子がhtmlのファイル名が入っているものとし、フォルダ内にある複数のshift_jisのhtmlファイルをutf-8に変換する場合のサンプルを挙げます(ただし、フォルダ名やファイル名に全角文字が含まれていると、正常にファイルをopenすることができませんので、注意してください。全角文字がフォルダ名やファイル名に含まれている場合は、ドライブ名から指定する絶対的なパスではなく、相対的なパスに変更して、フォルダ名に全角文字が入らないようにしたり、フォルダ名やファイル名を変更しておく必要があります。相対的なパスについては[2-1-4.スクリプトと入出力ファイルを異なるフォルダに入れる]を参照してください。)。

【スクリプト】
# open_pragma2.pl   
# 内容 : フォルダ内のファイルについてshift_jisからutf-8に変更する  
# Copyright (c) 2013 Mitsuo Minagawa, All rights reserved.  
# (minagawa@fb3.so-net.ne.jp)   
# 使用方法 : c:\>perl open_pragma2.pl   
#   
use open IN  => ":encoding(cp932)"; 
use open OUT => ":encoding(utf8)";  

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

    foreach $line   (@data)     {   
        $line   =~  s/charset=shift_jis/charset=UTF-8/g;    
    }       

# 読み込んだファイルを出力ファイルとして、openし直す    
    open(OUT1,">$filename");        

# 変更した内容を出力する    
    foreach $line   (@data)     {   
            print   OUT1    $line;  
    }   
}       
close(IN1);     
close(IN2);     
   
【スクリプトとデータのサンプル】

スクリプトはこちらにあります。




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