Home > Archives > 2008-08

2008-08

Python: 二値の交換

ソート系のアルゴリズムを実装する際などに、配列の任意の2つの要素を交換する処理が必要な場合がありますので、以下にその手順の一例を示します。

ソースコード

# coding: UTF-8

a = [10, 20]
print '%d %d' % (a[0], a[1])
a[0], a[1] = a[1], a[0]
print '%d %d' % (a[0], a[1])

実行結果

10 20
20 10

何だかperlの多重代入を思い出します。

ActionScript: マウスをイベントリスナーに登録

先ずは下のFlashの円にマウスポインタを合わせたり、クリック・ダブルクリックなどするとそれに伴ったアクションがあります

このFlashの仕様をコードに書きおこす際、1つのクラスに全ての機能を書き込む方法もありますが(この場合はその方がコード量が少なくなる)、折角なのでOOに基づいたコードを書いてみました。が、OOのパターンを適応途中に飽きたので少し崩しています(ぇー)。

ソースコード

上のFlashは以下の三つのクラスで描かれています。

  1. Main.as
  2. Ball.as
  3. EventMonitor.as

Main.as

MainクラスではマウスイベントをキャッチするBallクラス(後述)とその結果を観測し画面左上に出力するEventMonitorクラス(後述)のインスタンスを生成し画面への出力登録を行っています。ball変数をEventMonitorのコンストラクタに渡しているのはEventMonitorからマウス座標等を取得する為のballインスタンスのメソッドを呼び出すからです。

今回はイベントを発生させるオブジェクトがball一つですので後述のコードにしましたが、複数あるときはパターンに合わせた方が良いと考えます。

package info.yukun
{
  import flash.display.Sprite; // タイムラインを使わない場合、MovieClip より軽い

  public class Main extends Sprite
  {
    private var ball:Ball; // Ballクラス型の変数
    private var monitor:EventMonitor; // イベントのモニタリング用のクラス

    // コンストラクタ: ここからプログラムコードを読んでいく
    public function Main():void
    {
      init();
    }

    private function init():void
    {
      ball = new Ball(); // Ballインスタンスを作成
      ball.x = stage.stageWidth / 2; // オブジェクトの表示位置(中央)
      ball.y = stage.stageHeight / 2;
      ball.regEvent(); // マウスイベントリスナーの登録
      addChild(ball); // 最上位のSpriteにballオブジェクトを表示

      monitor = new EventMonitor(ball);
      monitor.x = 0; // 左上に設置
      monitor.y = 0;
      addChild(monitor);
    }
  }
}

Ball.as

次に、冒頭のFlashに描かれている青い円を描画するBallオブジェクトを読んでみましょう。先ず、コンストラクタのBallとinit()メソッドで青い円を描画しています。

次にregEvent()メソッドでイベントリスナーの登録手続きを書いています。大抵この規模のコードですとMain.asでball.addEventListener(ホニャララ)とリスナー登録しているコードを散見しますが、オブジェクトの振る舞いはオブジェクト毎に持たせた方がOOぽいし、何だか再利用できそうな希望の片鱗を与えてくれるのでBallクラスにregEvent()メソッドを付けてみました。これはMainクラスから呼び出されることで、ballのマウスのイベントリスナーの一括登録が行われます。

後の二つのメソッド、mousePosition()とgetState()はEventMonitorクラスから呼び出されるものです。このメソッドを通して、画面左上にマウス座標等を表示します。ここでも機能の分離を行っています。すなわち、情報を投げる側(Ball)と観測し表示する側(EventMonitor)です。

package info.yukun
{
  import flash.display.Sprite;
  import flash.events.MouseEvent; // マウスイベント用

  public class Ball extends Sprite
  {
    private var radius:Number; // 円の半径
    private var color:uint; // 色
    private var event_state:String; // イベントの状態

    public function Ball(radius:Number = 50, color:uint = 0xA3D5FF)
    {
      this.radius = radius;
      this.color = color;
      this.event_state = "";
      init();
    }

    public function init():void
    {
      graphics.beginFill(color);
      graphics.drawCircle(0, 0, radius); // 円の描画
      graphics.endFill();
    }

    // イベントリスナーの登録
    public function regEvent():void
    {
      // このオブジェクトにクリックが発生したら登録したメソッド(onMouseEvent)を実行、と読む
      addEventListener(MouseEvent.CLICK, onMouseEvent);
      doubleClickEnabled = true; // ダブルクリックの検出を可能にする
      addEventListener(MouseEvent.DOUBLE_CLICK, onMouseEvent);
      addEventListener(MouseEvent.MOUSE_DOWN, onMouseEvent);
      addEventListener(MouseEvent.MOUSE_MOVE, onMouseEvent);
      addEventListener(MouseEvent.MOUSE_OUT, onMouseEvent);
      addEventListener(MouseEvent.MOUSE_OVER, onMouseEvent);
      addEventListener(MouseEvent.MOUSE_UP, onMouseEvent);
      addEventListener(MouseEvent.MOUSE_WHEEL, onMouseEvent);
    }

    public function onMouseEvent(event:MouseEvent):void
    {
      event_state = event.type;
      trace(event_state);
      switch(event_state) {
        case MouseEvent.ROLL_OVER:
        this.color = 0x0006FA;
        init();
        break;
        case MouseEvent.ROLL_OUT:
        this.color = 0xA3D5FF;
        init();
        break;
      }
    }

    public function mousePosition():String
    {
      // この場合、軸の原点は円の中心(オブジェクトのSpriteを基準)
      return "("+ Math.floor(mouseX) + ", " + Math.floor(mouseY) + ")";
    }

    public function getState():String
    {
      return event_state;
    }
  }
}

EventMonitor.as

最後になりましたが、マウスイベントの内容やマウス座標の表示を行うEventMonitorクラスです。
ここでのイベントリスナーの登録は、

addEventListener(Event.ENTER_FRAME, onEnterFrame);

ですね。
フレームが更新される毎に、第二引数に登録したonEnterFrame()メソッドを実行します。Event.ENTER_FRAMEはアニメーションさせる時に良く使うプロパティですが、ここではマウス座標やマウスクリックイベント情報を取得し出力する為に使われています。

package info.yukun
{
  import flash.display.Sprite;
  import flash.events.Event;
  import flash.text.*;

  public class EventMonitor extends Sprite
  {
    private var ball:Ball; // 観測オブジェクト
    private var monitor_label:TextField; // 表示ラベル
    private var TITLE:String;

    public function EventMonitor(ball:Ball)
    {
      this.ball = ball;
      init();
    }

    public function init():void
    {
      TITLE = "イベントモニター";
      monitor_label = new TextField();
      monitor_label.text = TITLE;
      monitor_label.autoSize = TextFieldAutoSize.LEFT;
      monitor_label.selectable = false;
      addEventListener(Event.ENTER_FRAME, onEnterFrame);
      addChild(monitor_label);
    }

    private function onEnterFrame(event:Event):void
    {
      var text:String = TITLE + "\n";
      text += "マウス座標(原点はボールの中心): " + ball.mousePosition() + "\n";
      text += "発生イベント: " + ball.getState() + "\n";
      monitor_label.text = text;
    }
  }
}

AS3になりJavaやC#に似て格段に扱いやすくなったように感じます。OOはGUIにマッチする設計手法ですしね。
話し変わりますが、以前windows.hを用いたGUIのコードではイベントループで悪戦苦闘してたっけ。今なら多少は上手く書けるかな。どうだろ。

Python: 指定したパスのディレクトリ中のファイル一覧を出力

あるディレクトリから特定のファイルを検索したい場合、探索対象ディレクトリ内のファイルを全て取得する必要があります。今回は、引数にディレクトリを指すパスを指定することによって、そのディレクトリの内容を取得する関数を2つ示します。

ソースコード

# coding: Shift_JIS

import os # osモジュールのインポート

# os.listdir('パス')
# 指定したパス内の全てのファイルとディレクトリを要素とするリストを返す
files = os.listdir('C:\Python25\')

for file in files:
    print file

実行結果の一例

DLLs
Doc
include
Lib
libs
LICENSE.txt
lxml-wininst.log
NEWS.txt
PIL-wininst.log
pysqlite-wininst.log
pysqlite2-doc
python.exe
pythonw.exe
README.txt
Removelxml.exe
RemovePIL.exe
Removepysqlite.exe
Scripts
tcl
Tools
w9xpopen.exe

ワイルドカードでリスティング対象を指定

globモジュールのglob()関数の引数内にワイルドカード「*」を含めることが出来ます。これによって、より手軽に目的のファイルを探索することが出来ます。

ソースコード

# coding: Shift_JIS

import glob

# パス内の全ての"指定パス+ファイル名"と"指定パス+ディレクトリ名"を要素とするリストを返す
files = glob.glob('C:\Python25\*.*') # ワイルドカードが使用可能

for file in files:
    print file

os.listdir()と異なり、glob.glob()は取得したファイル文字列には先頭に探査ディレクトリ(引数)のパスが付いています。

実行結果の一例


C:Python25LICENSE.txt
C:Python25lxml-wininst.log
C:Python25NEWS.txt
C:Python25PIL-wininst.log
C:Python25pysqlite-wininst.log
C:Python25python.exe
C:Python25pythonw.exe
C:Python25README.txt
C:Python25Removelxml.exe
C:Python25RemovePIL.exe
C:Python25Removepysqlite.exe
C:Python25w9xpopen.exe

リファレンス

サイトURLの変更のお知らせ

この度、サイトURLを

http://trumpcode.yukun.info/

から、
http://blog.yukun.info/
http://www.yukun.info/
に変更しました。
それに合わせて、RSSも以下のように変更しました。
http://feedproxy.google.com/yukun-blog

まぁ、サブドメインをwwwとしました。URL短くなるし良いかなと思って(trumpcodeって一見で何だか分かんないね)。
一応、これまでのインデックスが消えるまでは、旧URLはリダイレクトでこちらに投げています。

Python: 正規表現の基本 - 最長、最短マッチング

直前の文字、メタ文字を繰り返しマッチングさせる量指定記号である「*」「+」「?」などは、テキスト中にその繰り返しパターンがマッチする箇所が複数ある場合は、通常最後にマッチした箇所をオブジェクトに記録します。このような最長マッチングに対して、マッチング箇所が複数の場合に最初にマッチした箇所を記録する最短マッチング方法があります。

最短マッチングを行う量指定記号は最長マッチングの記号の末尾に「?」を付けるだけです。すなわち、最長の量指定が「*」「+」「?」であるのに対して、最短マッチングは「*?」「+?」「??」となります。それでは、以下のコードで確認してみましょう。

ソースコード

# coding: Shift_JIS

import re # 正規表現を扱うモジュールのインポート

# 正規表現のチェックプリント用の関数
def PrintRegMatch(pat, txt):
    #   書式: re.search(パターン, テキスト)
    m = re.search(pat, txt) # パターンにマッチしなかった場合はNoneを返す
    if m != None:
        print 'パターン: "%s"nテキスト: "%s"nマッチ  : する' % (pat, txt)
        print 'マッチング開始位置:', m.start()
        print 'マッチング終了位置:', m.end()
    else:
        print 'パターン: "%s"nテキスト: "%s"nマッチ: しない' % (pat, txt)
    print
    return m

# サンプルテキスト
txt = '<p>Hello! World!!</p><p>Goodbye World</p>'
# 最長: .*
# 最短: .*?
PrintRegMatch('<p>.*</p>',  txt) # 最長: 文字列末尾の</p>にマッチ
PrintRegMatch('<p>.*?</p>', txt) # 最短: World!!</p>の</p>にマッチ

# 最長: .+
# 最短: .+?
PrintRegMatch('<p>.+</p>',  txt) # +?は直前の文字の1文字以上の繰り返し
PrintRegMatch('<p>.+?</p>', txt) # ↑の控えめマッチング

# 最長: .?
# 最短: .??
PrintRegMatch('B.?C',  'BCCC')   # ?は直前の文字の0 or 1回の繰り返し
PrintRegMatch('B.??C', 'BCCC')   # ??はその控えめ(ry

re.searchはre.matchと異なり、パターンをテキスト文字列の先頭以外にもマッチさせます。

実行結果

パターン: "<p>.*</p>"
テキスト: "<p>Hello! World!!</p><p>Goodbye World</p>"
マッチ  : する
マッチング開始位置: 0
マッチング終了位置: 41

パターン: "<p>.*?</p>"
テキスト: "<p>Hello! World!!</p><p>Goodbye World</p>"
マッチ  : する
マッチング開始位置: 0
マッチング終了位置: 21

パターン: "<p>.+</p>"
テキスト: "<p>Hello! World!!</p><p>Goodbye World</p>"
マッチ  : する
マッチング開始位置: 0
マッチング終了位置: 41

パターン: "<p>.+?</p>"
テキスト: "<p>Hello! World!!</p><p>Goodbye World</p>"
マッチ  : する
マッチング開始位置: 0
マッチング終了位置: 21

パターン: "B.?C"
テキスト: "BCCC"
マッチ  : する
マッチング開始位置: 0
マッチング終了位置: 3

パターン: "B.??C"
テキスト: "BCCC"
マッチ  : する
マッチング開始位置: 0
マッチング終了位置: 2

リファレンス

Page 1 of 3123

Home > Archives > 2008-08

バックナンバー
最近のコメント
最近のトラックバック
メタ情報

Return to page top