第9章 文字列とディレクトリの操作
9-1. コメント
プログラムを記述する際に、覚え書きという位置づけ等で、(プログラムには解釈されない形で)メモ情報を残しておきたいことがあります。
それを「コメント」と呼びます。
Perlでは、シャープ ( # ) から行末までを「コメント」として扱われ、プログラムの実行上無視されます。これを「コメントアウト」といいます。
コメントは、文の途中に記述しても構いません。その場合は、# から、行末までがコメントになります。
=pod =cutについては、プログラミング中やテスト中などに、「一時的に」複数行をコメントアウトしたい場合などにはよく使われる手法です。
それを「コメント」と呼びます。
Perlでは、シャープ ( # ) から行末までを「コメント」として扱われ、プログラムの実行上無視されます。これを「コメントアウト」といいます。
$data = 'I am a boy'; # データを記述 print "$data\n";上記のコードの場合、3行目がすべてコメントとして扱われます。
コメントは、文の途中に記述しても構いません。その場合は、# から、行末までがコメントになります。
$date = 'I am a boy'; print "$data\n"; # データを記述また、応用的な記述方法として、複数行をコメントアウトする場合には、次のように =pod から =cut を記述することで、その範囲がすべてコメント扱われます。
=pod これを用いると、 複数行に渡って コメント扱いされます =cut $data = 'I am a boy'; print "$data\n";ただし、実は上記の方法は正規なやり方ではありません。 複数行に渡ってコメントアウトしたい場合でも、本当は # を用いて行数分コメントアウトするのが基本です。
=pod =cutについては、プログラミング中やテスト中などに、「一時的に」複数行をコメントアウトしたい場合などにはよく使われる手法です。
9-2. ヒアドキュメント
複数行に渡る文字列を記述したり、データを代入するときに用いられるのが、ヒアドキュメントです。
ヒアドキュメントは、<< + [識別文字] から [識別文字] という書式で記述します。
たとえば、以下のような文を記述するケースがあったとします。
これをヒアドキュメントを用いて書くと、次のようになります。
上記の場合 [識別文字] を「EOM」にしていますが、この文字は任意で構いません。 ただし、通常は大文字にします。
また、[識別文字]を囲むダブルクォーテーションを省略しても構いません。 その場合は同じ意味(文字列をダブルクォーテーションで囲む)になります。
文字列をシングルクォーテーションで囲んだ場合と同じ扱いになります。
ヒアドキュメントは、<< + [識別文字] から [識別文字] という書式で記述します。
たとえば、以下のような文を記述するケースがあったとします。
print "How are you?\n"; print "Fine, Thank you. Are you?\n"; print "I am fine, too.\n";行ごとに print文を書かないといけないので、少し面倒です。
これをヒアドキュメントを用いて書くと、次のようになります。
print <<"EOM"; How are you? Fine, Thank you. Are you? I am fine, too. EOM便利な書き方ですね。
上記の場合 [識別文字] を「EOM」にしていますが、この文字は任意で構いません。 ただし、通常は大文字にします。
また、[識別文字]を囲むダブルクォーテーションを省略しても構いません。 その場合は同じ意味(文字列をダブルクォーテーションで囲む)になります。
print <<EOM; How are you? Fine, Thank you. Are you? I am fine, too. EOMさらに、[識別文字]をシングルクォーテーションで囲むと、囲まれた文字列については、変数展開がされなくなります。
文字列をシングルクォーテーションで囲んだ場合と同じ扱いになります。
print <<'EOM'; それはいくらですか? これは$100です。 EOM
> それはいくらですか? > これは$100です。ヒアドキュメントは、print文だけではありません。 たとえば、次のようにスカラー変数への代入時などにも使用されます。
$str = <<"EOM"; それは何ですか? これは檸檬です。 EOM print $str;
> それは何ですか? > これは檸檬です。
9-3. 文字列の検索
文字列を検索する関数として、index関数と rindex関数があります。
1. index関数
構文 |
---|
index ( 全体文字列, 検索文字列, 開始位置 ) index ( 全体文字列, 検索文字列 ) |
「全体文字列」の中で、「開始位置」の位置から「検索文字列」が最初に出現する位置を返す。
「開始位置」が省略されると、先頭から検索する。(先頭の位置は 0 とする)
検索して見つからなければ -1 を返す。
2. rindex関数
「開始位置」が省略されると、先頭から検索する。(先頭の位置は 0 とする)
検索して見つからなければ -1 を返す。
構文 |
---|
rindex ( 全体文字列, 検索文字列, 開始位置 ) rindex ( 全体文字列, 検索文字列 ) |
「全体文字列」の中で、「検索文字列」が最後に出現する位置を返す。
「開始位置」を付加することで、値として返すことが許される、最も右よりの位置を指定することができる。
検索して見つからなければ -1 を返す。
「開始位置」を付加することで、値として返すことが許される、最も右よりの位置を指定することができる。
検索して見つからなければ -1 を返す。
コード例-1
$str = "ABCDEF"; $sub = "CD"; $find = index($str, $sub); if ($find >= 0) { $find++; print "先頭から$find番目に見つかりました。\n"; } else { print "見つかりませんでした。\n"; }
> 先頭から3番目に見つかりました。
「コード例-1」では、最初に見つかった部分を表示させていますが、文字列の中で見つかるものすべてを表示させたい場合には、次の「コード例-2」のように記述します。
コード例-2
$str = "apple orange banana"; $sub = "a"; while ( ($find = index($str, $sub, $find) ) >= 0 ) { $find++; print "$find番目に発見。\n"; }
> 1番目に発見。 > 9番目に発見。 > 15番目に発見。 > 17番目に発見。 > 19番目に発見。
9-4. 文字列の操作
文字列を操作する関数として、substr関数があります。文字列の取り出し、置き換え、削除、追加などを行うことができます。
構文 |
---|
substr ( 全体文字列, 開始位置, 文字長 ) substr ( 全体文字列, 開始位置 ) |
「全体文字列」から部分文字列を取り出して返す。
部分文字列は、文字列の先頭から数えて「開始位置」番目から始まる(先頭は 0 から数える)。
「開始位置」が負の場合は、文字列の末尾からマイナス「開始位置」文字だけ戻ったところが部分文字列の先頭になる。
「文字長」を省略すると、文字列の末尾までがすべて返される。
部分文字列は、文字列の先頭から数えて「開始位置」番目から始まる(先頭は 0 から数える)。
「開始位置」が負の場合は、文字列の末尾からマイナス「開始位置」文字だけ戻ったところが部分文字列の先頭になる。
「文字長」を省略すると、文字列の末尾までがすべて返される。
文字列の取り出し
$word = "milktea"; $str = substr($word, 0, 4); print "$str\n";
> milk
substr関数を左辺に置き、代入の対象とすることで、部分文字列の置き換えや追加などが可能となります。
文字列の置き換え
$word = "milktea"; substr($word, 0, 4) = "lemon"; print "$word\n";
> lemontea
文字列の削除(先頭から削除)
$word = "milktea"; substr($word, 0, 4) = ""; print "$word\n";
> tea
文字列の削除(末尾から削除)
$word = "milktea"; substr($word, -3, 3) = ""; print "$word\n";
> milk
9-5. 文字列の整形
文字列を整形する関数として、printf関数 と sprintf関数 があります。文字列や数値を指定の書式に変換を行います。
printf関数 は整形した値をファイルハンドルに出力し、sprintf関数 は整形した値を返します。
printf関数 は整形した値をファイルハンドルに出力し、sprintf関数 は整形した値を返します。
関数 | 構文 | 内容 |
---|---|---|
printf関数 | printf ( 書式, リスト ) | 「リスト」の値を「書式」に整形して、ファイルハンドルに出力する。 |
sprintf関数 | sprintf ( 書式, リスト ) | 「リスト」の値を「書式」に整形して、その値を返す。 |
構文における書式のコードは次のとおりです。
コード例
コード | 意味 |
%c | 文字 |
%s | 文字列 |
%d | 10進整数 |
%e | 浮動小数点数(指数形式) |
%f | 浮動小数点数(固定小数点形式) |
%e | 浮動小数点数(コンパクト形式) |
%o | 8進整数 |
%x | 16進整数 |
%X | 16進整数(大文字使用) |
$hour = 5; $min = 12; $sec = 6; $time = sprintf("%02d:%02d:%02d", $hour,$min,$sec); print "$time\n";
> 05:12:06
9-6. ディレクトリの読み取り
ディレクトリの中身を読み取るための関数として、opendir関数、readdir関数、closedir関数があります。
ファイルをオープンするときにopen関数でファイルハンドルを関連付けますが、それと同じように、ディレクトリをオープンするときには、ディレクトリハンドルを指定して関連付けを行います。
ファイルをオープンするときにopen関数でファイルハンドルを関連付けますが、それと同じように、ディレクトリをオープンするときには、ディレクトリハンドルを指定して関連付けを行います。
opendir関数でディレクトリをオープンする場合は、読み出し専用であることに注意します。
open関数のように、ファイルの追加や書き込みなどを行うことはできません。
関数 | 構文 | 内容 |
---|---|---|
opendir | opendir ( ディレクトリハンドル, ディレクトリ ) | 「ディレクトリ」で与えられたディレクトリ名をオープンする。成功すれば真を返す。 |
readdir | readdir ( ディレクトリハンドル ) | opendirによってオープンされた「ディレクトリハンドル」から、ディレクトリエントリを読む。 |
closedir | closedir ( ディレクトリハンドル ) | opendirによってオープンされたディレクトリを閉じる。 |
現在のディレクトリの中身を読み取って表示させる例です。
コード例-1
コード例-1
use strict; opendir(DIR, "."); my @dir = readdir(DIR); closedir(DIR); foreach (@dir) { next if (/^\.{1,2}$/); # . と .. を排除 print "$_\n"; }
上記のコード例では、ディレクトリの中身を一気に読み込んで配列@dirに代入する例ですが、1行ずつ読み出す場合には、次のように記述することもできます。
ディレクトリの中に多くのファイルがあることが予想される場合に有効です。
コード例-2
ディレクトリの中に多くのファイルがあることが予想される場合に有効です。
コード例-2
use strict; opendir(DIR, "."); while( my $dir = readdir(DIR) ) { next if ($dir =~ /^\.{1,2}$/); # . と .. を排除 print "$dir\n"; } closedir(DIR);
ディレクトリ内の情報を読み取るものとして、他に次のような関数/演算子も用意されています。
glob関数とダイヤモンド演算子は使い方は同じです。
元々ダイヤモンド演算子のみであったものが、Perl5からその関数として、glob関数が登場したということのようです。
関数/演算子 | 構文 | 内容 |
---|---|---|
glob関数 | glob( 式 ) |
「式」はワイルドカードを使ったファイル名。省略時は$_になる。 引数の「式」にマッチしたファイル名のリストを返す。 |
ダイヤモンド演算子 | < 式 > | 同上 |
コード例-3
use strict; # ディレクトリ内の情報を読み出す my @dir = glob('*'); print join("\n", @dir), "\n"; # ディレクトリ内の情報を読み出す my @dir = <*>; print join("\n", @dir), "\n";上記のglob関数とダイヤモンド演算子の場合は、同じ結果が得られます。
ワイルドカードを使って、取得するファイルを指定することもできます。
コード例-4
(1) 取得するリストで、ファイルがABC順に並ぶ。
(2) ワイルドカート ( * ) のみではドットファイルは得られない。
(3) 異なるディレクトリで取得する場合、リストはパス付きで得られる。
コード例-4
# ディレクトリ内の拡張子が.htmlのみのファイルを読み出す my @dir = glob('*.html'); print join("\n", @dir), "\n"; # ディレクトリ内の拡張子が.htmlと.plを読み出す(複数の場合はスペースで区切る) my @dir = glob('*.html *.pl'); print join("\n", @dir), "\n";glob関数(ダイヤモンド演算子)の利用において、opendir関数との主な違いは、次のとおりです。
(1) 取得するリストで、ファイルがABC順に並ぶ。
(2) ワイルドカート ( * ) のみではドットファイルは得られない。
(3) 異なるディレクトリで取得する場合、リストはパス付きで得られる。
ドットファイルも取得したい場合には、次のようにします。
コード例-5
コード例-6
出力結果の2行目は、opendir関数の例で、ファイル名のみが取得されます。
コード例-5
use strict; my @dir = glob('* .*'); # .* でドットファイルを得る print join("\n", @dir), "\n";異なるディレクトリを読み出す場合のopendirとの比較です。
コード例-6
use strict; # glob関数で異なるディレクトリ読み出し my @dir = glob('./dir/*'); print join("\n", @dir), "\n"; # opendir関数で異なるディレクトリ読み出し opendir(DIR,"./dir"); my @dir = readdir(DIR); closedir(DIR); for (@dir) { next if (/^\./); print "$_\n"; }
> ./dir/abc.html > abc.html出力結果の1行目は、glob関数の例で、「パス付き」で取得されます。
出力結果の2行目は、opendir関数の例で、ファイル名のみが取得されます。
9-7. ディレクトリの生成と削除
ディレクトリを生成したり、削除するための関数として、mkdir関数とrmdir関数があります。
関数 | 構文 | 内容 |
---|---|---|
mkdir | mkdir ( ディレクトリ名, モード ) | ディレクトリ「ディレクトリ名」を作成し、そのパーミッションを数値「モード」にする。 成功すれば 1 を返し、失敗すると 0 を返す。 |
rmdir | rmdir ( ディレクトリ名 ) | 「ディレクトリ名」に指定したディレクトリが空きならば、これを削除する。 成功すれば 1 を返し、失敗すると 0 を返す。 「ディレクトリ名」を省略すると、$_ が使われる。 |
ディレクトリの作成
mkdir("./dir", 0755) or die;ディレクトリの削除
rmdir("./dir") or die;
mkdir関数の使用時に注意する点として、たとえばパーミッションを「777」のディレクトリを作成する場合、次のような一行を記述しても実際には777で生成されません(環境にもよりますが、大抵は755になります)。
mkdir("./dir", 0777);この場合には、その前にumask関数でumask値を0にすると、思い通りのパーミッションになります。
umask(0); mkdir("./dir", 0777);
ちなみに、umask値とは、ファイル・ディレクトリの新規作成時に適用されるマスク値のことです。
通常は、「022」に設定されているため、mkdir関数で「777」で生成しようとしても、777 - 022 = 755 となってしまいます。
そこで、umask関数で意図的にこれを「000」に変更することで、777 - 000 = 777 にするということになります。
そこで、umask関数で意図的にこれを「000」に変更することで、777 - 000 = 777 にするということになります。