Perlプログラミング - 最初の一歩

いよいよPerlのプログラミングを開始します。通常の入門書であれば、変数の定義の仕方や基本的な制御構造から入るところですが、ここでは手っ取り早くPerlプログラミングの雰囲気を掴んで頂くため、Perlらしい特徴的な機能を使ったサンプルプログラムをいくつか紹介していきたいと思います。

  1. Perlのインストール確認
  2. まずは、Perlの準備ができているか確認をします。「インストール」の章の通りにインストールが完了していれば、コマンドラインから、

    $ perl -v⏎
    
    This is perl 5, version 12, subversion 1 (v5.12.1) built for darwin-2level
    (〜以下省略〜)
    の様にコマンドを投入して、上記の様に(5.12.1を示す)バージョン番号が表示されるはずです。なお、「built for」以降はOSによって異なりますので、上記の通り表示されなくても心配はいりません。

    「perl」はプログラミング言語Perlの実行コマンドです。引数に「-v」を付けると、バージョンを表示します。

    本書は全てPerl 5.12.1をベースに検証していますので、バージョンが合っているか、必ず確認して下さい。

    上記の様に表示されない場合は、再度「インストール」の章を参照して正しくインストールされているかチェックして下さい。

  3. ワンライナー(One Liner)
  4. Perlも他の一般的なインタプリタ型プログラミング言語と同様に、予めテキストエディタでソースコードを作成し、言語の実行コマンドにソースコードを引き渡す事でプログラムを起動します。
    しかし、Perlにはワンライナー(One Liner)という機能が有り、直接Perlの実行コマンドの引数にPerlのプログラムそのものを引き渡すことができます。これにより、コマンドラインからPerlのプログラムを直接実行でき、いちいちテキストエディタを立ち上げる必要が無いので、素早く結果が得られます(図1参照)。使いこなすと非常に便利で強力な機能です。

    図1 - Perlのプログラムの起動方法の比較(クリックすると大きな画像が開きます)

    One Liner

    ここではこのワンライナーを使ってPerlのプログラミングの最も最初のステップを解説します。

    実はワンライナーはあまりに多彩な機能が有って、実に奥が深く、Perlの中でも上手く使いこなすのが難しい機能の一つですが、基本となる部分は難しくは有りません。以降しばらくワンライナーの最も基本的な機能だけを使ってPerlの基本を学んでいくことにします。

    では、実際に使っていってみましょう。

    1. 「Hello, World」の表示
    2. まずはプログラミング言語習得の第一歩「Hello, World」の表示から。

      コマンドラインから、

      $ perl -e 'print "Hello, World\n"'⏎
      と投入します。結果は、
      Hello, World
      と表示されます(最後は改行されます)。

      ちょっと分かりづらいのですが、上記の-eの後ろは、シングルクォーテーション → print → ダブルクォーテーション→ Hello, World\n → ダブルクォーテーション → シングルクォーテーションの順に入力します。

      では、このコマンドの構成を説明します(図2参照)。

      図2 - ワンライナーの構成(クリックすると大きな画像が開きます)

      One Liner

      一つ一つワンライナーの構成要素を見ていきましょう。

      • perl
      • 最初の「perl」は、Perlのインタプリタ実行コマンドの指定です。

      • -e
      • 「続く引数をPerlのプログラムとして解釈する」という指定です。

      • プログラム本体 - print "Hello, World\n"
      • Perlのプログラムその物です。シングルクォーテーションか、ダブルクォーテーションで囲みます。 今回はプログラム中にダブルクォーテーション(")を使っているので、区別するためにシングルクォーテーション(')を使用しました。

      • 組み込み関数print
      • printはperlの組込関数で、続く引数の内容を標準出力に出力します。
        デフォルトでは、結果は画面に表示されます。

      • 組み込み関数printの引数 - Hello, World\n
      • printは引数で与えられた文字列を標準出力に出力します。ここでは引数の文字列をダブルクォーテーション(")で囲っています。引数の最初の「Hello, World」はそのまま表示されます。

      • メタキャラクター:\n
      • Hello, Worldの後ろの「\n」は、改行を表すメタキャラクターです。print関数の引数がダブルクォーテーションで囲まれている時、メタキャラクターは、それを表す内容に変換されます。この場合は改行が行われます(\nは改行を表すメタキャラクターです)。
        なお、print関数の引数がシングルクォーテーションで囲まれている時はメタキャラクターの変換は行われません。そのまま「\n」と表示されます。

      「Hello, World」を表示したら...

      「Hello, World」の表示の次のステップは、やはりメッセージの変更です。色々と試してみましょう。

      • 「Hello, World」を書き換える。
      • まずは「Hello, World」を何でもいいので書き換えてみましょう。日本語でもOKです。

      • ダブルクォーテーションとシングルクォーテーションを入れ替える。
      • 表示がどの様に変わるのか確認してみましょう。

      • 文字列の中にダブルクォーテーションを使う。
      • 文字列をダブルクォーテーションで囲んでいますが、文字列の中にダブルクォーテーションを使いたい時はどうするのでしょうか?
        そんな時は、ダブルクォーテーションを表すメタキャラクター「\"」を使います。

      • 他のメタキャラクターを使う。
      • メタキャラクターには改行を示す「\n」だけでなく、タブを表す「\t」や、警告音を鳴らす「\a」などが有ります。

      • シングルクォーテーションの中でメタキャラクターを使う。
      • ダブルクォーテーションの中はメタキャラクターが変換されると書きましたが、実は一つだけシングルクォーテーションで囲まれた文字列の中でも別の字に変換されるメタキャラクターが有ります。それはシングルクォーテーション自身を表す「\'」です。これも試してみて下さい。

      もっと先のステップで学ぶこと...

      ダブルクォーテーションで囲んだ文字列ではメタキャラクターを変換する事を学びました。しかし、実は変換されるのはメタキャラクターだけではありません。Perlでは、変数の内容も変換することができます。これはもっと先の章で学ぶことになります。

    3. 繰り返し実行する

    4. Perlで作る定番のプログラムと言えば、CSVなどのテキストファイルを行単位に処理するフィルタ系ツールです。1行ずつ行単位にテキストファイルに読み込み、結果を同じ様に行単位に出力する、という処理を繰り返し、入力が続く限り実行します。こうする事で少ないメモリで巨大なテキストファイルを処理する事ができます。

      ワンライナーではオプションを一つ追加するだけで、この繰り返し処理が実現できます。さっそくサンプルを見てみましょう。

      まずは入力のテキストファイルを用意します。

      InputSample.csv

      aaa,bbb⏎
      ccc,ddd⏎
      eee,fff⏎
      
      最後のfffの後は改行を入れます。なお、テキストファイルの文字コードは使っているターミナルの環境変数に設定されている文字コードに合わせて下さい。最近のLinuxやMac OS XであればUTF-8になるでしょう。ターミナルの文字コードは、LinuxやUnixであればecho $LANG調べられます。

      テキストファイルが用意できたら、

      $ perl -ne 'print ++$i . $_' InputSample.csv⏎
      と投入します。

      結果は、

      1aaa,bbb
      2ccc,ddd
      3eee,fff
      4
      と表示されます。

      では、このコマンドの構造を説明します(図2参照)。

      図2 - ワンライナーでのループ実行の構成(クリックすると大きな画像が開きます)

      One Liner Loop

      こちらも、一つ一つ見ていきましょう。

      • -ne
      • eオプションの前に「n」オプションが指定されています。これは標準入力から入力されるテキストファイルを1行ずつ処理しなさい、というオプションです。この指定により、入力の数だけ-eオプションの引数に指定されているスクリプトが実行されます。
        上記の例では、InputSample.csvは4行なので、ワンライナーは4回実行されます。

      • ++$a
      • 詳細はのちほど説明しますが、Perlでは一つの値を格納する変数は「$」で始まる名前を付けます。その前の「++」はC言語でもおなじみのインクリメント演算子です。C言語と同様に前置のインクリメント演算子は、その変数が使われる前に変数の内容を一つ増加させます。
        つまり、入力のテキストファイルの行数分だけ変数の値は一つずつカウントアップされるわけです。

      • $_
      • 先に「$_」変数を紹介します。「$_」変数はPerlが予め用意している特殊変数で、今処理している入力の行データがそのまま格納されています。

      • .
      • 「.」(ドット演算子)は、「++$i」と、「$_」を文字列として連結します。

      たったこれだけで入力のテキストファイルに行番号を付与するスクリプトになりました。

      繰り返し実行したら...

      繰り返し実行の基本を理解したら、次は繰り返される内容を変えてみましょう。色々と試してみましょう。

      • 固定の文字列を連結する。
      • ダブルクォーテーションで囲んだ文字列を「.」(ドット演算子)で連結すれば、固定の文字列を全ての行に付加することができます。

      • 結果を元のファイルへ書き戻す。
      • perl -i -ne 'print ++$i . $_' InputSample.csv」と-iオプションを指定すると、結果を元のファイルへ書き戻す事ができます。結果はすぐに確認できますが、書き換わっています。

      もっと先のステップで学ぶこと...

      ここまでの説明ではあまり便利さが分からないワンライナーの繰り返しですが、次に説明する正規表現によるパターンマッチと組み合わせると、自由自在に入力のテキストを加工して結果を出力する、といったPerlの最も強力な機能を利用することができるようになります。

  5. 正規表現(Regular Expression)
  6. Perlの特徴の一つとして、強力なテキスト処理機能が挙げられますが、その最も中心的な機能が「正規表現によるパターンマッチ」です。

    早速例を見てみましょう。

    ReSample-1.log

    x0010 2010/1/1 01:23:11 200⏎
    a00233 2010/3/10 10:11:23 404⏎
    x0010 2010/10/1 23:33:21 300⏎
    単純なアクセスログらしきデータです(ユーザID、アクセス日、アクセス結果...と理解して下さい)。

    このログの中から時刻だけを抜き出したいという要望が出たとします(平均的なアクセス時刻を知りたいのでしょう...)。まさか一行ずつエディタで確認しながら、時刻らしきデータをコピペするわけにはいきません(3行くらいだったら何とかなるかもしれませんが、1000行を超えていたら...)。

    残念な事にユーザーIDや、日付の書式が可変長文字列なので、文字位置と長さを決め打ちで抜き出す事もできません。しかし、時刻のデータはhh:mm:ddと形式が決まっています。この様な"データの形式(pattern)"に注目して文字列の検索を行うのが「正規表現によるパターンマッチ」なのです。

    さて、実際にワンライナーで記述すると、

    $ perl -ne 'print "$1\n" if /(\d\d:\d\d:\d\d)/' ReSample-1.log⏎
    となります。

    実行した結果は、

    01:23:11
    10:11:23
    23:33:21
    
    と、確かに時刻部分だけが表示されました。

    ではこのコマンドの構造を説明しましょう。ちょっと順序は逆ですが。

    • //
    • //で囲まれた中には正規表現による検索条件を記述します。

    • \d\d:\d\d:\d\d
    • 「\d」は、数値1文字を表すメタキャラクターです。つまり、上記の例では、数値2桁ずつ、計3つをコロンで連結した文字列を示します。先ほどの時刻データの"形式"そのものですね。

    • if
    • ifはPerlにおける条件分岐です。ifの後ろに、条件式を記述します。条件が満たされた時、ifの前の文が実行されます。つまり、日本語で書くと「○○を実行しなさい、ただし××が成立するなら...」という解釈をするわけです。

    • $1
    • 上記の例では、\d\d:\d\d:\d\dが括弧で囲まれている所に注目して下さい。Perlでは、正規表現による検索が成功した時(条件に合致する文字列が存在する時)、括弧に囲まれた正規表現に該当する文字列を特殊変数$1に保存します。
      つまり、\d\d:\d\d:\d\dというパターンに合致した具体的な文字列の内容を取得できるのです。
      ちなみに同じ正規表現の中に括弧が複数存在する場合は、$2、$3と数値が増えていきます。

    ちょっと駆け足すぎましたが、最もキャッチーで最もこれからも普通に使いそうな機能から紹介してみました。一歩戻って、もう一回説明してみます。

    普通の検索

    数値の検索

    文字数を指定した検索

    応用編

    文字の検索

    行頭、行末の検索

    次のステップ

    キャプチャ

    オプション

    選択

    その他のメタ文字

  7. ハッシュ変数(Hash Variables)
  8. スカラーコンテキストと、リストコンテキスト(Scalar Context and List Context)

以下、執筆中

トラックバックURL

このエントリーのトラックバックURL:
http://ash.roova.jp/mt/mt-tb.cgi/184

コメントする