5.0 置き換え

ある特定の文字を別の文字に変更することは、Perl を使う場合良くあります。 置き換えは、 s/パターン/置換したい字/ で行います。
(例題 5.0) 全角の数字、1、2、3を半角の数字 1,2,3 に置き換えます。(p5-0.pl) 日本語コードを含んでいる場合には、EUC コードにプログラムやデータを変換する必要があります。 (変換の方法は、% nkf -e file.any > file.euc です。nkf を使う場合には 入力 file がどのコードであっても構いません。)
#!/usr/local/bin/perl
while (<>) {  # 標準入力から1行づつ読んで以下を処理
s/1/1/go;     # 1 を 1 に換えます。g = 1行に 2個以上あっても処理  
s/2/2/go;     # 2 を 2 に換えます。この処理は 同じ $_ に対して実行
s/3/3/o;     # 3 を 3 に換えます。
print;         # 結果を印刷します。
}              # while の終了です。

ここで、g と o は変換の際のオプションで、

g = grobal (1 行の中で該当する全部を変換する。) 
o = one time (検索するパターンが、変数でないので Perl に 1 度
              だけ、コンパイルさせる。処理速度が速くなる。)
となっている。オプションがある場合と無い場合の違いについて、 実験してみると良い。

p5-0.dat を以下の用に EUC コードで作り、実行する。

123456 全角の文字 123456
123456 全角の文字 123456
112233445566 半角の文字 112233445566
% p5-0.pl < p5-0.dat
123456 全角の文字 123456
123456 全角の文字 123456
112233445566 半角の文字 112233445566
%
のように 3 は、行の最初に現れた 3 のみ処理をしている。

p5-0.plのように変換規則を並べれば良いので、処理時間を特に 気にしなければ簡単にプログラムが作れます。処理時間を調べたい時には、

% time p5-0.pl < p5-0.dat

でできる。0.020u 0.060s 0:00.09 は それぞれ user の使用した時間、system が利用した時間、その合計です。時間の単位は 秒です。

5.1 パターンの取り出し方

表から特定の列の部分を取り出すのは、2.3 で split を用いて 配列に代入する方法が有効である。ここでは、特定のパターンを持った 行の情報を取り出す方法について説明する。
(例題 5.1) 特定の部分を $_ から取り出して印刷する。(p5-1.pl) 通常は while(<>) {....} とするが、ここでは $_ の内容がわかり やすいようにプログラムを作った。
#!/usr/local/bin/perl
$_ = 's9510245 斎藤 理一郎 125 24 35 Saitou'; # $_ を定義
print /郎 (.*)Saitou/,"\n"; # 郎 と Saitou の間にある部分を印刷。
@a = /郎 (.*)Saitou/; print @a, "\n"; # ( ) の部分は、配列 @a に入る。
print /.9510(.*)/,"\n"; # . は任意の1文字で、9510に続く行の残りを印刷
print /[a-z]9510(.*)/,"\n";# 最初の1文字は、a-z の文字に限定する。
print /\w9510(.*)/,"\n";# これでも可。\w はアルファベット文字を指す。
print /[a-z]9[45]10(.*)/,"\n"; # 9410 か 9510 のみ印刷。

(...) ではさまれている部分が取り出される。取り出された部分は、 (...) が現れた順に $1、$2 ... と入る。s/../../ の中で使用し たい場合には、\1、\2、として使えば良い。(例: s/ab(.*)cde/AB\1CDE/ では ab と cde に挟まれた任意の文字を AB と CDE に挟むように置き換えるものである。) ここで、

. は任意の1文字である。

* は0回以上の繰り返しである。従って、.* は 任意の文字列 となる。

+ は 1 回以上の繰り返しである。

[...] は その中から範囲で選択となる。[0-9]+ の様に記すと、数 字の繰り返しになる。これは\d (数字) で置き換えられる。また [a-z] は \w (アルファベット文字 と _) で置き換えられる。この ような表現は正規表 現と呼ばれる。詳しくは、マニュアルを参考にして下さい。

特に検索部分を 変数に代入する場合には、($hensuu) = / ... / を 用いる。例えば file=a.eps を取り出したい場合には、= の前 後に space がある可能性に注意すれば、

($file) = /file[ ]*=[ ]*(.*).eps/ ; # (.*) が検索部分。[ ]* は可能なスペースの部分。

と書けば良い。($file) の (...) がないと、true or false が入る。

5.2 if 構文での使用法

もしパターンがあったら、処理をするという形は、

if(/パターン/){...} # パターン が あったら {...} を処理。

という文で行われる。置換をして処理することもできる。

if(s/パターン/置換/){...} # パターンがあったら置換を行い {...} を処理。

これは、パターンがあった場合には、/パターン/ が、if の文で 1(真) を与え、 また s/パターン/置換/ によって置換がうまくできた場合には、if の文で 1(真) を与えるからである。(print /パターン/; で確かめよ。)


(例題 5.2) $_ のなかに、特定の pattern があった場合に処理をします。(p5-2.pl) また、pattern があった場合 があった場合どのような値を返すかを示します。
#!/usr/local/bin/perl
$_ = 's9510245 斎藤 理一郎 125 24 35 Saitou'; # $_ を定義
# もし $_ に Saitou があれば あったことを印刷。
if (/Saitou/) { print "Saitou san is found.\n" }
# もし $_ に Saitou があれば Saitou を Saito に 変換して印刷。
if (s/Saitou/Saito/) { print "Found: ==> ",$_,"\n"}
# こういう文法も ok です。この場合でも 置換をさきにします。
print "Found: ==> ",$_,"\n" if (s/Saito/Saitoh/);
# /Saitoh/ がある場合にはどんな値を返すかを示します。
print /Saitoh/,"\n";
# /Saitou/ はありません。この場合にはどんな値を返すかを示します。
print /Saitou/,"\n";

実行結果を示します。
% p5-2.pl
Saitou san is found.
Found: ==> s9510245 斎藤 理一郎 125 24 35 Saito
Found: ==> s9510245 斎藤 理一郎 125 24 35 Saitoh
1
     <== パターンばない場合には、何も返しません。        
%