ファイル入出力とデータ処理

ここでは今まで学習してきたPerlの特長を活かして、下記の内容を、実際のデー タを利用して演習していきます。

使用するデータは下記の2種類です。それぞれの中身を見てください。

  1. 千葉市の2000年の公示地価:CSVファイル
  2. 千葉県の市町村名:テキストファイル

上記の1つ目のファイルは、各データがカンマ区切りで格納されたCSVファイルで す。1番目の項目には「中央」「市川」「酒々井」のように、市町村名の一 部か区名(千葉市のみ)が記入されてます(「酒々井」は「印旛郡酒々井町」で す)。また3番目の項目には市町村名以外の住所が記入されています。

ここで、達成すべき目標を明確にすると、

「中央」と「新千葉3丁目320番」のデータから「千葉市中央区新千葉3丁目 320番」のような、正式な住所を生成する

ということです。その結果、

「正式な住所」「対象年価格」「前年価格」から構成される データをファイルに出力

したいとします。このWebページでの学習により、 この出力ファイルを作成できるようになり ます。

ファイル入出力

下記の内容を、テキストエディタ(LinuxであればEmacs、Windowsであれば秀丸 など)を用いて記述しましょう。 lesson1-1.plというファイル名で、 ホームディレクトリの下に作ったperlというディレクトリ に保存しましょう。

#!/usr/bin/perl

$file="kouji_2000.csv";

open (IN, $file) or die "$!";

while (<IN>) {
    print $_;
}

close (IN);

このlesson1-1.plを実行させますが、LinuxとWindowsで実行のための手順が異なり ます。ここではLinuxの環境について説明していきます。lesson1-1.plがある ディレクトリperlに移動します。その後、実行させます。

% cd perl
% ./lesson1-1.pl

または、

% cd perl
% perl lesson1-1.pl

Windowsの場合、こちらの ページを参照してください。

この結果、"kouji_2000.csv"に記述されている各行が表示されるはずです。 ここで確認しましょう。

while (<IN>) {
    print $_;
}

この意味は、

<IN> 開いたファイルを1行単位で読み込み
print $_; 1行単位で読み込んだデータをそのまま表示
while( ) { } 行が存在する限り繰り返す

これと同じことは、下記のように書いても実現します。

@lines = <IN>;
foreach (@lines) {
    print $_;
}

としても同じ結果になります。この場合、

@lines = <IN> 開いたファイルを1行単位で配列@linesに格納
foreach ( ) { } 配列の要素数だけ繰り返す

という意味です。どちらも使えるようになりましょう。


さて、今度はファイルへの出力の練習です。出力用のファイルも指定します。 lesson1-1.plに赤字で示された文字列を追加して、 lesson1-2.plという名前で保存しましょう。その後、実行させて、出力ファイルの kouji_2000_out.csvの中身がkouji_2000.csvと同じかどうか確認してみましょう。

#!/usr/bin/perl

$file="kouji_2000.csv";
$outfile="kouji_2000_out.csv";

open (IN, $file) or die "$!";
open (OUT, ">$outfile") or die "$!";

while (<IN>) {
    print OUT $_;
}

close (IN);
close (OUT);

UNIXでの実行結果の確認:出力ファイルの表示

% cat kouji_2000_out.csv

(または)
% more kouji_2000_out.csv

(または)
% less kouji_2000_out.csv

行データの分割

各行のデータを単に表示させるだけでは意味がありません。そのデータから必要 な部分だけ切り出して、操作することは多々あります。今回の目標に置いても、 1番目の項目(「千葉中央」「酒々井」など)と3番目の項目(「新千葉3丁目 320番」など)を利用して、住所を生成したいわけです。そのためにも、各行の データを分割する必要があります。

それでは、下記のスクリプトをlesson2-1.plという名前で 保存してください。lesson1-2.plに対し、赤字で示された部分を追加し、別名で 保存すればすぐに完成します。

#!/usr/bin/perl

$file="kouji_2000.csv";
$outfile="kouji_2000_out.csv";

open (IN, $file) or die "$!";
open (OUT, ">$outfile") or die "$!";

while (<IN>) {

    # 改行コードの除去
    chomp ($_);

    # 各行をカンマ区切りで分割
    @data = split(/,/, $_);

    # 全角、半角空白の除去
    for ($i=0; $i<@data; $i++) {
        $data[$i] =~ s/( | )+//g;
    }

    print OUT "$data[0], $data[1], $data[2]\n";
}

close (IN);
close (OUT);

実行した後に、出力ファイルを確認するとわかりますが、0番目、1番目、2番目 の項目のデータのみが出力されています。上記のスクリプトにおいては、 下記のような意味があります。

chomp ($_); 改行文字があれば削除
@data = split(/,/, $_); $_ を , を区切りとして分割し、配列@dataに格納
$data[0] 配列@dataの0番目の要素

分割データの検索、置換

Perlでよく使われる便利な機能に、この文字列の検索、置換があります。 特定の文字列が含まれていれば特別な処理をしたい場合、または特定の文字列を 削除したい場合などにも利用されます。

ここでは、下記のスクリプトをlesson3-1.plというファ イル名で保存してください。元となるファイルはlesson2-1.plで、赤字で記され た部分を追記したものです。

#!/usr/bin/perl

$file="kouji_2000.csv";
$outfile="kouji_2000_out.csv";
@chiba_ku = ('中央', '花見川', '稲毛', '若葉', '緑', '美浜');

open (IN, $file) or die "$!";
open (OUT, ">$outfile") or die "$!";

while (<IN>) {

    # 改行コードの除去
    chomp ($_);

    # 各行をカンマ区切りで分割
    @data = split(/,/, $_);

    # 全角、半角空白の除去
    for ($i=0; $i<@data; $i++) {
        $data[$i] =~ s/( | )+//g;
    }

    foreach $key (@chiba_ku) {
        if ($data[0] =~ /$key/) {
            print OUT "$data[0]\n";
        }
    }
}

close (IN);
close (OUT);

上記のスクリプトでは、

@chiba_ku 千葉市の6つの区を要素とする配列
if ($data[0] =~ /$key/) { } $data[0]に$keyが含まれ ていれば真として、{ }の中身を実行

として、配列@chiba_kuの要素を取り出して、それぞれの要素の値(千葉市の区 名)が、公示地価のファイルの0番目の要素($data[0])に含まれるかを チェックしています。もし含まれていれば、printでファイルに出力するように 指示しています。出力ファイルのkouji_2000_out.csvの中身を確認しておきましょ う。

つづいて、下記のスクリプトをlesson3-2.plというファ イル名で保存してください。lesson3-1.plに対して、赤字で記され た部分を追記したものですが、一部、削除してある箇所もあるので注意深く 比較しながら作成してください。

#!/usr/bin/perl

$file="kouji_2000.csv";
$cityfile="chiba_city_name.txt";
$outfile="kouji_2000_out.csv";


open (IN, $file) or die "$!";
open (CITY, $cityfile) or die "$!";
open (OUT, ">$outfile") or die "$!";
@city = <CITY>;

# 市町村データの改行コードの除去
for ($i=0; $i<@city; $i++) {
    chomp ($city[$i]);
}

while (<IN>) {

    # 改行コードの除去
    chomp ($_);

    # 各行をカンマ区切りで分割
    @data = split(/,/, $_);

    # 全角、半角空白の除去
    for ($i=0; $i<@data; $i++) {
        $data[$i] =~ s/( | )+//g;
    }


    # 千葉がつくデータ名の変更
    if ($data[0] =~ /千葉/) {
        $data[0] =~ s/千葉//;
    }

    # 市町村名と各データの第1列とのマッチング
    foreach $cityname (@city) {
        if ($cityname =~ /$data[0]/) {
            print OUT "$cityname\n";
            last;
        }
    }

}

close (IN);
close (CITY);
close (OUT);

最後に、当初の目標を達成するスクリプトとして、 下記のスクリプトをlesson3-3.plというファ イル名で保存してください。lesson3-2.plに対して、赤字で記され た部分を追記したものですが、

正式な住所, 対象年価格, 前年価格

を、各行ごとに出力しています。出力ファイルの中身を確認してください。 この出力ファイルになるはずです。

#!/usr/bin/perl

$file="kouji_2000.csv";
$cityfile="chiba_city_name.txt";
$outfile="kouji_2000_out.csv";


open (IN, $file) or die "$!";
open (CITY, $cityfile) or die "$!";
open (OUT, ">$outfile") or die "$!";
@city = <CITY>;

# 市町村データの改行コードの除去
for ($i=0; $i<@city; $i++) {
    chomp ($city[$i]);
}


while (<IN>) {

    # 改行コードの除去
    chomp ($_);

    # 各行をカンマ区切りで分割
    @data = split(/,/, $_);

    # 全角、半角空白の除去
    for ($i=0; $i<@data; $i++) {
        $data[$i] =~ s/( | )+//g;
    }

    # 千葉がつくデータ名の変更
    if ($data[0] =~ /千葉/) {
        $data[0] =~ s/千葉//;
    }

    # 市町村名と各データの第1列とのマッチング
    foreach $cityname (@city) {
        if ($cityname =~ /$data[0]/) {
            print OUT "$cityname$data[2],$data[4],$data[5]\n";
            last;
        }
    }

}

close (IN);
close (CITY);
close (OUT);

課題

上記の「kouji_2000_out.csv」をテキストエディタやExcel上で開き、 1頁目だけ印刷して提出せよ。その際には、学籍番号と氏名を明記するように。


[Perl講座]
[ArcGIS/ArcMapの使い方] [地理情報システム論]
[須崎純一トップページ]
須崎純一 京都大学大学 工学研究科都市環境工学専攻 環境情報学講座