Help us understand the problem. What is going on with this article?

[Perl] ファイルを読み込みコメント行と空行以外を表示

More than 1 year has passed since last update.

まえがき

台風による悪天候で暇なので、気まぐれで記事を書いてみます。
世の中の流れは「とにかく Python」って感じですが、
最近は個人的に Perl に触れる機会があったので
復習も兼ねて記事に残してみます。備忘録程度です。
Better な書き方があれば是非ご教授くださいませ。。

概要

指定されたファイルを読み込み、
コメント行(# で始まる行)と空行を除いて
標準出力に出力するだけのプログラム remove_comments.pl を書きました。

[MBA ~/work/perl]$ cat test.txt 

hoge

# hogehoge
    # huga
    huga

### hugahuga

[MBA ~/work/perl]$ 
[MBA ~/work/perl]$ perl remove_comments.pl test.txt 
hoge
    huga
[MBA ~/work/perl]$ 

引数がなかったり、2つ以上指定されていた場合はエラー終了します。
指定されたファイルが無い場合もエラー終了します。
(エラーメッセージの雑さは許してください)

[MBA ~/work/perl]$ perl remove_comments.pl test.txt /etc/hosts
Invalid arguments
[MBA ~/work/perl]$ perl remove_comments.pl
Invalid arguments
[MBA ~/work/perl]$ perl remove_comments.pl hoge
hoge: No such file or directory
[MBA ~/work/perl]$ 

コード

以下が実装です。

remove_comments.pl
use strict;
use warnings;

use constant {
    EXIT_SUCCESS => 0,
    EXIT_FAILURE => 1,
};

our %ERR_MSG = (
    'INVALID_ARGS'      => "Invalid arguments\n",
    'FILE_NOT_FOUND'    => "No such file or directory\n",
    'CANNOT_OPEN_FILE'  => "Cannot open file\n",
    'CANNOT_CLOSE_FILE' => "Cannot close file\n",
);

main();

sub main {
    check_args();
    my ($filename) = @ARGV;
    open my $fh, "<", $filename or die "$filename: $ERR_MSG{CANNOT_OPEN_FILE}";
    my $match_pattern = '^\s*(#.*|)$';
    while (my $line = <$fh>) {
        chomp $line;
        if ($line !~ $match_pattern) {
            print "$line\n";
        }
    }
    close $fh or die "$filename: $ERR_MSG{CANNOT_CLOSE_FILE}";
    return EXIT_SUCCESS;
}

sub check_args {
    my $ARGS_NUM = 1;
    if (@ARGV != $ARGS_NUM) {
        print STDERR "$ERR_MSG{INVALID_ARGS}";
        exit EXIT_FAILURE;
    }
    my ($filename) = @ARGV;
    if (!-f $filename) {
        print STDERR "$filename: $ERR_MSG{FILE_NOT_FOUND}";
        exit EXIT_FAILURE;
    }
}

1;

__END__

お約束部分・定数定義部分

use strict;
use warnings;

use constant {
    EXIT_SUCCESS => 0,
    EXIT_FAILURE => 1,
};

our %ERR_MSG = (
    'INVALID_ARGS'      => "Invalid arguments\n",
    'FILE_NOT_FOUND'    => "No such file or directory\n",
    'CANNOT_OPEN_FILE'  => "Cannot open file\n",
    'CANNOT_CLOSE_FILE' => "Cannot close file\n",
);

main();

use strict; use warnings; はつけましょう。お約束。
use constant で定数を定義しています。TURE/FALSE なども、しばしば定義します。
our %ERR_MSG でグローバル変数によりエラーメッセージを定義しています。
実際は定数定義用のモジュールを作って、それを use するのがよいと思います。
今回はコードの練習ということで...

引数チェック: check_args()

引数の数の確認および指定されたファイルの存在を確認します。

sub check_args {
    my $ARGS_NUM = 1;
    if (@ARGV != $ARGS_NUM) {
        print STDERR "$ERR_MSG{INVALID_ARGS}";
        exit EXIT_FAILURE;
    }
    my ($filename) = @ARGV;
    if (!-f $filename) {
        print STDERR "$filename: $ERR_MSG{FILE_NOT_FOUND}";
        exit EXIT_FAILURE;
    }
}

メインルーチン: main()

sub main {
    check_args();
    my ($filename) = @ARGV;
    open my $fh, "<", $filename or die "$filename: $ERR_MSG{CANNOT_OPEN_FILE}";
    my $match_pattern = '^\s*(#.*|)$';
    while (my $line = <$fh>) {
        chomp $line;
        if ($line !~ $match_pattern) {
            print "$line\n";
        }
    }
    close $fh or die "$filename: $ERR_MSG{CANNOT_CLOSE_FILE}";
    return EXIT_SUCCESS;
}

open my $fh, "<", $filename で、ファイルを読み出します。書き込みのときは ">"
これもほぼお約束で、ファイルオープンに失敗した場合に異常終了するように、or die をつけます。

while (my $line = <$fh>) {...} で、ファイルハンドラから一行ずつ取り出して
それを $line に格納します。単に while (<$fh>) {...} だと $_ に格納されます。
デフォルト変数は便利ですが、可読性を損ねることがあるので私はあまり好まないです。

my $match_pattern = '^\s*(#.*|)$' で正規表現のパターンを定義しています。
このパターンにマッチしないものが欲しいので、
if ($line !~ $match_pattern) {...} とします。
マッチしたものが欲しいときは if ($line =~ $match_pattern) {...} です。
マッチした部分の文字列が欲しい場合は、パターン文字列の対象箇所を()で括った上で
$1, $2 などの変数を用いて参照します。詳細はここには書きません。

close $fh でファイルを閉じます。
学生時代、実家の冷蔵庫を開けたままでお茶を飲んでたらよく親から
「開けたら閉める!!」と叱られたものです(10秒くらいいいじゃん、って思います)。
ファイルも同じ、開けたら閉めましょう。
Python の with open(file) as f: みたいなの、Perl にもないかな...

おわりに

Perl の基本的な記事を書いて読む人っているのでしょうか。
Qiita を眺めてても Python / DeepLearning の記事が多い印象です。
私もトレンドに乗っかって、Python を完全に理解したいものです。

なお、本記事の内容を Python で書いた記事もあります。
(https://qiita.com/okateim/items/6e0955eac1fb66a8981e)

同じ内容で言語を変えたときにPV数にどれくらい差がでるのだろうと
気になって同じ内容2言語で書いてみた次第です。
(やっぱり Python のほうがたくさん見られてるみたいです)

okateim
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした