■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-2.文字コードの変換(perl IO レイヤ使用)

perl IO レイヤを利用して、入力ファイルの文字コードを変更する方法です。Perl5.8以降では、open関数で引数が3つとれるようになり、第1の引数はファイルハンドル、第2の引数は文字コード、第3の引数はファイル名を指定します。このうち、文字コードを指定する第2の引数は以下のように指定します。

  入力ファイルの場合、「"<:encoding(文字コード)"」
  出力ファイルの場合、「">:encoding(文字コード)"」
    

文字コードに具体的に何を指定するかについては下記の表を参照してください。

perl IO レイヤで指定できる文字コード(入出力ファイル両方で指定可)

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

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

perl IO レイヤで指定できる文字コード(入力ファイル専用)

文字コード 内    容
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)」を採用しています。

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

【スクリプト】
# perl_layer.pl
# 内容 : shift_jis形式のデータを読み込んでutf-8で出力する 
# Copyright (c) 2011 Mitsuo Minagawa, All rights reserved.
# (minagawa@fb3.so-net.ne.jp)
# 使用方法 : c:\>perl_layer.pl

# 入力ファイルは文字コードを Shift_JIS と指定.
open(IN1,  "<:encoding(shift_jis)", "input_sjis.txt");
# 出力ファイルは UTF-8 とする
open(OUT1, ">:encoding(utf8)", "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つずつ解説していきましょう。

# 入力ファイルは文字コードを Shift_JIS と指定.
open(IN1,  "<:encoding(shift_jis)", "input_sjis.txt");
# 出力ファイルは UTF-8 とする
open(OUT1, ">:encoding(utf8)", "output.txt");
   

入力ファイルの文字コードを指定するには、open関数の第2の引数で行います。Perl IO レイヤで指定する文字コードについては上記の表を参照してください。


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

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

use utf8;
# 入力ファイルは文字コードを Shift_JIS と指定.
open(IN1,  "<:encoding(shift_jis)", "input_sjis.txt");
# 出力ファイルは UTF-8 とする
open(OUT1, ">:encoding(utf8)", "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モジュールを利用する場合は、以下のようにします。

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

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

# 入力ファイルは文字コードを Shift_JIS と指定.
open(IN1,  "<:encoding(shift_jis)", "input_sjis.txt");
# 出力ファイルは UTF-8 とする
open(OUT1, ">:encoding(utf8)", "output.txt");
    

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

# perl_layer.pl
# 内容 : shift_jis形式のデータを読み込んでutf-8で出力する 
# Copyright (c) 2011 Mitsuo Minagawa, All rights reserved.
# (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;

# 入力ファイルは文字コードを Shift_JIS と指定.
open(IN1,  "<:encoding(shift_jis)", "input_sjis.txt");
# 出力ファイルは UTF-8 とする
open(OUT1, ">:encoding(utf8)", "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.スクリプトと入出力ファイルを異なるフォルダに入れる]を参照してください。)。

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

# 入力ファイルは文字コードを shift_jis と指定.  
open(IN1, "<:encoding(shift_jis)", "filename.txt"); 

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

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

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

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

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




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