以下のスクリプトはCSVファイルを読み込み、入力項目の項目数を制限してタブ区切りファイルとして出力するPerlのスクリプトです。
「2-1-1.スクリプトの基本形」で述べたスクリプトに多少手を加えることで、基本的なスクリプトからさまざまな処理を行うスクリプトが作成できるようになります。ここからは、基本的なスクリプトについて、いろいろなバリエーションがあることについて説明していきます。
入力データを編集して、出力データを作成する場合、入力データのうちの一部の項目だけを出力する場合があります。リレーショナル・データベース(relational data base)でいうところの射影(projection)に相当するものですが、このような場合、配列の要素を1つずつ指定していく方法と以下、説明するsplice関数を利用する方法があります。
splice関数の機能は、「元の配列」の「開始位置」から「要素の個数」分を抜き出して、別の配列(または文字列)に入れ、「元の配列」の「開始位置」からの配列の要素を指定した配列や文字列で置き換えるというものです。
要素の個数が1つの場合は文字列がセットされ、要素の個数が2つ以上の場合は配列がセットされます。指定方法は、別の配列(または文字列) = splice(元の配列,開始位置,要素の個数,置き換える配列)の形式で行います。4番目の引数である「置き換える配列」は、抜き出した配列を別な配列に置き換える場合に指定します。配列を抜き出すだけであれば、特に指定しません。その場合は、配列を置き換える処理は行われません。配列または文字列を抜き出す処理だけが行われます。
「2-1-1.スクリプトの基本形」のスクリプトを元に入力データの中の2番目から4番目までの項目だけを出力するスクリプトを具体的に例示しましょう。
抜き出す項目が少ない場合は、「out1 = join("\t",$in1[1],$in1[2],$in1[3]);」のように配列の要素を個別に「$in1[1]」などと指定していく方法を採るのが普通です。また、抜き出す項目が多い場合は、splice関数で「@temp = splice(@in1,1,3)」のように配列を抜き出してから、join関数でまとめる方法を採ります。
なお、配列全体を示すときは、「@in1」のように変数名の先頭に「@」(アットマーク)をつけ、配列の要素を個別に指定するときは、「$in1[0]」のように変数名の先頭が「$」(ドル記号)とし、変数名の後に「[ ]」(ブラケット)をつけて、その中に何番目の要素かを示す添字を記入します(例:$in1[0]など)。
ただし、Perlでは何番目かを数えるために"0"から始めるという点は、間違えやすいので、注意してください。繰り返しになりますが、添字の[0]は要素の1番目を示し、添字の[1]は要素の2番目を示すことになります。
# inout2.pl # 内容 : 基本プログラム(1件入力し、1件出力するプログラム) # Copyright (c) 2002 Mitsuo Minagawa, All rights reserved. # 使用方法 : c:\>perl inout2.pl # open(IN1,"input.txt"); #(1)入力ファイルをオープンする。 open(OUT1,">output.txt"); #(2)出力ファイルをオープンする。 while ($line1 = <IN1>) { #(3)1行単位で入力し、 #入力データが終了するまで繰り返す。 chomp($line1); #(4)行末の改行文字をカットする。 @in1 = split(",",$line1,-1); #(5)カンマで項目を分割する。 #抜き出す項目が少ない場合(2番目の項目から4番目の項目を抜き出す) $out1 = join("\t",$in1[1],$in1[2],$in1[3]); #抜き出す項目が多い場合(2番目の項目から4番目の項目を抜き出す) # @temp = splice(@in1,1,3); # $out1 = join("\t",@temp); #(6)タブで項目をまとめる。 print OUT1 "$out1\n"; #(7)1行出力する。 } close(IN1); #(8)入力ファイルをクローズする。 close(OUT1); #(9)出力ファイルをクローズする。
splice関数で注意すべき点は、この関数で指定した「元の配列」は、指定した「要素の個数」を抜き出した後の状態に変更されてしまうということです。
具体的には、下記のスクリプトを見てください。入力データには、項目が5つずつあり、その中の2番目の要素(2番目の引数は、"1"となっているが、Perlの配列は"0"から数えるため、"1"は2番目の項目になることに注意)から、3つ分を抜き出す処理を行っています。
言い換えれば、配列の中の2番目から4番目までの要素を抜き出す処理をしているのですが、この結果、「元の配列」は1番目と5番目の要素だけになっています。
したがって、この処理をした後、5番目の要素を抜き出すために「splice(@in1,4,1)」などとしても、「元の配列」には、2番目の要素までしかないため、何もセットされなくなってしまいます。
このため、元の配列に対して、splice関数を利用する場合は、1回しか利用しない場合を除いて、一度別の配列に保存しておき、利用する前に元に戻す操作が必要になります。具体的には、「@save1 = @in1」のようにしておき、利用前に「@in1 = @save1」の用に戻してからsplice関数を適用するのです。
aaa,1111,1000,2000,3000 bbb,2222,1000,2000,3000 ccc,3333,1000,2000,3000
1111 1000 2000 2222 1000 2000 3333 1000 2000
splice関数で具体的に何を行っているかが、わかるようにしているのが、以下のスクリプトです。入力データと出力データを比較してみると、splice関数が何をしているかがわかります。
# inout3.pl # 内容 : splice関数のテスト # Copyright (c) 2002 Mitsuo Minagawa, All rights reserved. # 使用方法 : c:\>perl inout3.pl # open(IN1,"input.txt"); open(OUT1,">output.txt"); # # 入力データが終了するまで繰り返す。 # while ($line1 = <IN1>) { chomp($line1); # 抜き出す前の配列 @in1 = split(",",$line1,-1); $out1 = join(",",@in1); print OUT1 "$out1\n"; # splice関数で抜き出した後の配列 @tmp = splice(@in1,1,3); $out1 = join(",",@in1); print OUT1 "$out1\n"; # splice関数で抜き出した配列 $out1 = join(",",@tmp); print OUT1 "$out1\n"; } close(IN1); close(OUT1);
aaa,1111,1000,2000,3000 bbb,2222,1000,2000,3000 ccc,3333,1000,2000,3000
aaa,1111,1000,2000,3000 # splice関数を使う前の @in1の内容 aaa,3000 # splice関数を使った後の @in1の内容 1111,1000,2000 # splice関数を使った後の @tmpの内容 bbb,2222,1000,2000,3000 # splice関数を使う前の @in1の内容 bbb,3000 # splice関数を使った後の @in1の内容 2222,1000,2000 # splice関数を使った後の @tmpの内容 ccc,3333,1000,2000,3000 # splice関数を使う前の @in1の内容 ccc,3000 # splice関数を使った後の @in1の内容 3333,1000 # splice関数を使った後の @tmpの内容