作者: 閑舎
日時: 2006/7/06(00:03)
皆さん、こんにちは。

最近 PHP でクラスを使うのに慣れたいと思っていろいろやっている私です。

例えば、以下のコードは、改行が連続すると段落 p が始まるととらえ(他のタグ
はないと仮定する単純な解析器)、

 ab
 c

 def

という文字列を、

 <p>ab
 c</p>
 <p>def</p>

というようにタグ付けしてくれるものです。

Block というクラスには、解析を受け持つ parse とタグ化を受け持つ toText 
メソッドがあり、これを拡張(extends)した Body, P というクラスにも受け継が
れています。

$body = new Body(0) は $body = new Block("body", 0) と同じものなので、こ
の場合、Body, P クラスを作るのはある意味資源の浪費なのですが、まあ、もう
少しいろいろ作っていくとたぶん役に立つだろうということです(^^;。

こうしてできた PHP のコードを、Perl とか、ruby とか、Python とかで書くと
一体どんな感じになるのでしょう? 私はこうしたオブジェクト指向の表現にあ
まり慣れていないので、純粋に知りたいです。

<?php
$line = "\n\nab\nc\n\ndef";
$length = strlen($line);
$pt = 0; // $line の処理中のポインタ

$body = new Body(0); // $body = new Block("body", 0); と等価
$body->parse(); // 解析し next を作る
$body->toText(); // html出力

class Block {
  function Block($name, $start) { // Block クラスの初期化
    list($this->name, $this->next, $this->start, $this->len) = array($name, null, $start, 0);
  }
  function parse() {
    global $line, $length, $pt;
    if (preg_match("/\n\n+/", $line, $matches ,PREG_OFFSET_CAPTURE, $pt)) {
      $this->len = $matches[0][1] - $this->start;
      $pt = $matches[0][1] + strlen($matches[0][0]);
      $this->next = new Block("p", $pt);
      $this->next->parse();
    } else if ($this->name != "body") {
      $this->len = $length - $this->start;
      $this->next = new Block("body", $length);
    }
  }
  function toText() {
    global $line;
    if ($this->name != "body") echo "<" . $this->name . ">";
    echo substr($line, $this->start,  $this->len);
    if ($this->name != "body") echo "</" . $this->name . ">\n";
    if ($this->next != null) $this->next->totext();
  }
}
class Body extends Block {
  function Body($start) {
    parent::Block("body", $start);
  }
}
class P extends Block {
  function P($start) {
    parent::Block("p", $start);
  }
}
?>

--
本田博通(閑舎)
テキストとスクリプトの http://www.rakunet.org/TSNET/