Category Archives: プログラミング

プログラミング

PHPExcelでセルの入力規則に名前定義を使う方法

Published by:

PHPExcelとはPHPでExcelを読み書きするための便利ツールですが、一度はまると泥沼に陥りやすいので、取り扱いに非常~に注意が必要です。

そんな泥沼の一つからやっと生還したので、ブログに書き残しておこうと思います。

上手のようなものをPHPExcelで動的に行おうと思ったのですが、ニッチもサッチもいかない。
「Excel2007」のWriterだと $validation->setFormula1(‘=野菜’); で簡単に出来るのですが、要件的にExcel2003への対応が必須だったため、どうしても「Excel5」のWriterで吐き出される必要がある。

最終的にうまくいったのですが、PHPExcelのコードの修正が必要です。

■PHPExcel/Writer/Excel5/Worksheet.php(PHPExcel 1.7.7)
2844:                // formula 1
2845:                try {
2846:                    $formula1 = $dataValidation->getFormula1();
2847:                    // >>> Added by S.Sakai
2848://                    if ($type == 0x03) { // list type
2849:                    if ($type == 0x03 && preg_match('/^\".*\"$/', $formula1)) { // list type
2850:                    // <<< Added by S.Sakai

2851:                        $formula1 = str_replace(',', chr(0), $formula1);
2852:                    }
2853:                    $this->_parser->parse($formula1);
2854:                    // >>> Added by S.Sakai
2855:                    if (is_array($this->_parser->_parse_tree)
2856:                            && strtoupper($this->_parser->_parse_tree['value']) == 'INDIRECT') {
2857:                        $this->_parser->_parse_tree['force_reference'] = true;
2858:                    }
2859:                    // <<< Added by S.Sakai

2860:                    $formula1 = $this->_parser->toReversePolish();
2861:                    $sz1 = strlen($formula1);
2862: 
2863:                } catch(Exception $e) {
2864:                    $sz1 = 0;
2865:                    $formula1 = '';
2866:                }

■PHPExcel/Writer/Excel5/Parser.php(PHPExcel 1.7.7)
616:    // >>> Added by S.Sakai
617://    function _convertFunction($token, $num_args)
618:    function _convertFunction($token, $num_args, $force_reference)
619:    // <<< Added by S.Sakai

620:    {
621:        $args = $this->_functions[$token][1];
622://        $volatile = $this->_functions[$token][3];
623:
624:        // Fixed number of args eg. TIME($i,$j,$k).
625:        if ($args >= 0) {
626:            return pack("Cv", $this->ptg['ptgFuncV'], $this->_functions[$token][0]);
627:        }
628:        // Variable number of args eg. SUM($i,$j,$k, ..).
629:        if ($args == -1) {
630:            // >>> Added by S.Sakai
631://            return pack("CCv", $this->ptg['ptgFuncVarV'], $num_args, $this->_functions[$token][0]);
632:            if ($force_reference) {
633:                return pack("CCv", $this->ptg['ptgFuncVar'], $num_args, $this->_functions[$token][0]);
634:            } else {
635:                return pack("CCv", $this->ptg['ptgFuncVarV'], $num_args, $this->_functions[$token][0]);
636:            }
637:            // <<< Added by S.Sakai

638:        }
639:    }


1571:        // if it's a function convert it here (so we can set it's arguments)
1572:        if (preg_match("/^[A-Z0-9\xc0-\xdc\.]+$/",$tree['value']) and
1573:            !preg_match('/^([A-Ia-i]?[A-Za-z])(\d+)$/',$tree['value']) and
1574:            !preg_match("/^[A-Ia-i]?[A-Za-z](\d+)\.\.[A-Ia-i]?[A-Za-z](\d+)$/",$tree['value']) and
1575:            !is_numeric($tree['value']) and
1576:            !isset($this->ptg[$tree['value']]))
1577:        {
1578:            // left subtree for a function is always an array.
1579:            if ($tree['left'] != '') {
1580:                $left_tree = $this->toReversePolish($tree['left']);
1581:            } else {
1582:                $left_tree = '';
1583:            }
1584:            // add it's left subtree and return.
1585:            // >>> Added by S.Sakai
1586://            return $left_tree.$this->_convertFunction($tree['value'], $tree['right']);
1587:            return $left_tree.$this->_convertFunction($tree['value'], $tree['right'], $tree['force_reference']);
1588:            // <<< Added by S.Sakai

1589:        } else {
1590:            $converted_tree = $this->_convert($tree['value']);
1591:        }

CONCATENATE(“野菜”)の部分をCONCATENATE(“野菜_”,A2)のように変えれば、ほかのセルの入力値を使ってさらに動的な入力規則を設定できるようになりますよ。

今日は丸一日これにドはまりでした。
PHPExcelには、このページをそのまま通知しようかな。。

あ、あとPHPExcelで困っている人にお勧めなのが、下の2つです。

それではお休みなさい (つ_-*)。οΟ ゜

プログラミング 学習 発表、ニュース

Ajaxプログラミング講座と「団話」

Published by:

リアルタイムチャットシステムの団話(だんわ)っていうのをリリースしました。
今年の春頃に、必要があってちょっと作ったものですが、数あるリアルタイムチャットと比べて、これがすごい!!というのは今のところありません。
ただ、来週から開催予定の「Ajaxプログラミング講座」で活用できないかと、公開サーバー上に上げてみたというところです。

で、「Ajaxプログラミング講座」ですが、要するに今どきのWebアプリを作るときにはマスト技術であるJavaScriptをみっちり学ぼうという趣旨のものです。

夜19時から21時半までの2時間半×4回の日程で(場所は四谷三丁目)、まだまだまだ空きがありますので、気になる方はご参加をご検討くださいませ。

参加できないよ~という方も、団話でもしかしたら感触を見られるかもしれませんので、乞うご期待!
ちっとも団話に上がってこない可能性もありますので、そこのところはご容赦を~。

団話の今後の展開としては、API化して、いくつか検討中の仕組みに組み込もうかと思っています。

プログラミング 学習

最高の教育とは

Published by:

最近ビル・ゲイツ氏の教育関係の記事をよく目にしますが、すごく真剣に教育のことを考えているんでしょうね。

ビル・ゲイツが考える世界一の大学はどこにある?
これから5年間、Webで世界一良い講義を見つけ出すことができるようになるでしょう。しかも無料で。それは、単一の大学で学ぶよりも、はるかに良いでしょう。

 
私はここ最近、教育のあり方というものについて、必ず梶川泰司さんの書かれたことを念頭に置くようにしています。
その文章をの全文を、ここに転載させていただきます。

教えること – 犬のしっぽ ブログ
最高の授業には最高の教師と最高の生徒が必要だ
という前提から入学制度が維持されている。
彼らは入学試験の難易度を誇りにしている。

最高の教育は、子どもが子どもを教えるプロセスにある。
教師も教科書もそれほど重要ではない。
宇宙についてほとんど知らないと言う前提が
そのプロセスを生成する。

宇宙の統合性について知りたいという要求が
しばしばこどもに新しい言語を生成させる。

その場面に教師が立ち会うことはほとんど稀だ。
この自己教育の経験が彼らの子ども時代にすでに
欠乏しているからである。

 
最高の教師(もしくは最高の教材)+最高の生徒こそが最高の授業を作るという発想は、多くの教育の場で見つけることが出来るのではないでしょうか。

私も新社会人の方向けにプログラミングを教えるという仕事をしていますが、受講生同士による学びあいや発見の重要性、テキスト至上主義による弊害は身にしみて感じています。

本来プログラミングなどの専門知識を学ぶには、自己教育+経験(フィードバック)こそが有効だと思います。
専門知識は、教師から生徒に向けた、テキストに書かれている言葉だけでは伝わらないことが多いように感じます。
学ぶ本人が、「自分が理解する」という意識をもち、そこを教師や教材がサポートするということが肝心ではないでしょうか。

それでも、中には自己教育の経験を持たないままに社会人になられた方もいて、テキストがあっても、教師がいても、はたまた受講生同士の学びあいの場をもたせても、「自分が理解する」ことを理解していない方は、一歩も先に進めないのです。

ゲイツ氏は、高校3年生までは物理的な学校が必要ということを述べており、大学というものが日本と海外では役割や性格が違っているということも含めると、Webこそが最高の「専門知識の」教育を提供するということを伝えていらっしゃるのだと思いますし、私も同意です。

しかし、Webを介した専門知識教育を享受できるのは、自己教育のすべを持っているひとだけではないでしょうか。
日本では特に、自己教育そのものを体得することが出来る教育体系になっていないと実感しています。
幼児から大人になるまでの間に、自己教育というものを経験できる世界になるよう、私もいつか何かの形で貢献できればと思っています。

CMS プログラミング

WordPressなどのソース一式をzip圧縮してダウンロードする方法

Published by:

レンタルサーバーでWordPressなどのCMSを動かしている方は数多くいるかと思いますが、sshやtelnetアクセスができないサーバーも意外に多くあります。
その場合、FTPで時間をかけて何百、何千というファイルをアップロード、ダウンロードしなければいけません。

アップロードについてはすでに「unzip.zip」という素晴らしいツールがありますので、みなさまそちらを使いましょう。

今回ここで紹介するのは、zipで圧縮してまとめてダウンロードする方法です。

zipdownload.zip

上のプログラムをGET&解凍して出て来るzipdownload.phpを、まとめてダウンロードしたいディレクトリの中にアップロードします。
WordPressの場合は、wp-contentとか、wp-config.phpなどのファイルがあるところにアップすればよいかと思います。

ここまで出来れば、後はブラウザで http://xxx/zipdownload.php のようにリクエストしてください!
download.zipという名前でダウンロードが開始されます。

ダウンロードが終わった後に zipdownload.php を必ず削除してくださいねー

プログラミング

「PHP使いはもう正規表現をblogに書くな」のメールアドレスチェック用正規表現をPHP用に書きなおす

Published by:

メールアドレスをチェックする機能を作るときに、これまで2度「PHP使いはもう正規表現をblogに書くな」と言わせないでくれ / 404 Blog Not Foundを参考にさせていただきましたが、何故か(よっぽどお怒りだったのか?)PHPでは直接使えない記述になっていましたので、毎回自分で修正して使っていました。
今後も使いたい正規表現ですので、PHPでの実装コードと、JavaScript版の実装コードをメモします。

小飼 弾さんの作られたオリジナル正規表現

/^(?:(?:(?:(?:[a-zA-Z0-9_!#\$\%&'*+/=?\^{}~|\-]+)(?:\.(?:[a-zA-Z0-9_!#\$\%&'*+/=?\^{}~|\-]+))*)|(?:"(?:\\[^\r\n]|[^\\"])*")))\@(?:(?:(?:(?:[a-zA-Z0-9_!#\$\%&'*+/=?\^{}~|\-]+)(?:\.(?:[a-zA-Z0-9_!#\$\%&'*+/=?\^{}~|\-]+))*)|(?:\[(?:\\\S|[\x21-\x5a\x5e-\x7e])*\])))$/

PHP用の実装コード

if (!preg_match('/^(?:(?:(?:(?:[a-zA-Z0-9_!#\$\%&\'*+\/=?\^{}~|\-]+)(?:\.(?:[a-zA-Z0-9_!#\$\%&\'*+\/=?\^{}~|\-]+))*)|(?:"(?:\\[^\r\n]|[^\\"])*")))\@(?:(?:(?:(?:[a-zA-Z0-9_!#\$\%&\'*+\/=?\^{}~|\-]+)(?:\.(?:[a-zA-Z0-9_!#\$\%&\'*+\/=?\^{}~|\-]+))*)|(?:\[(?:\\\S|[\x21-\x5a\x5e-\x7e])*\])))$/', $email)) {
    $error = '正しいメールアドレスを入力してください。';
}

ereg関数を使えばオリジナル正規表現のままでよいのですが、preg*の方が一般的だと思います。
ここでは「’」と「/」をエスケープしています。

JavaScript用の実装コード

if (!email.match(/^(?:(?:(?:(?:[a-zA-Z0-9_!#\$\%&'*+\/=?\^{}~|\-]+)(?:\.(?:[a-zA-Z0-9_!#\$\%&'*+\/=?\^{}~|\-]+))*)|(?:"(?:\\[^\r\n]|[^\\"])*")))\@(?:(?:(?:(?:[a-zA-Z0-9_!#\$\%&'*+\/=?\^{}~|\-]+)(?:\.(?:[a-zA-Z0-9_!#\$\%&'*+\/=?\^{}~|\-]+))*)|(?:\[(?:\\\S|[\x21-\x5a\x5e-\x7e])*\])))$/)) {
    error = "正しいメールアドレスを入力してください。";
}

JavaScriptは正規表現リテラルが使えますので、「/」のみをエスケープしています。

ただ、この正規表現では「da.me..@docomo.ne.jp」といったRF2822非準拠の携帯メールアドレスがエラーで弾かれるんですよね。
これをdocomoの変メールへの対応バージョンは・・・次の人にまかせた!

プログラミング 発表、ニュース

100のソフトウェアアイディア

Published by:

停滞気味のドラゴンレーダーはさておき、・・・本当はさておきたくないのですが、、どうしても「遊びの」時間を作れないので、ともかくも作りたいと思ったものをどんどんアウトプットしていこうと思います。
こうでもしないと、頭の中がパンクしそうなんです。

本当にしょうもないものから、誰かの役になりそうなものまで、次々にソフトウェアを作る欲求がとめどなくあふれて来るのです。
これまで未完成のアイディアをブログに書いたりするのは、何となくもったいない感じ(誰かにアイディアだけ真似されたくない)がしていたのですが、どうせ作れないのなら同じだっと開き直ることにしました。

むしろ誰かに作ってほしいものばかりなので(少なくとも私が欲しいものばかり)、もしこんなのすでにあるよ~とか、作ってみたよ何てすばらしい方がいらっしゃれば、コメント下さいませ。

idea

100個出るかはわかりませんが・・・(ーー;

プログラミング

Eclipse:WTPプロジェクトで外部プロジェクトのクラスを参照&デプロイ

Published by:

ここより

A. 別ブロジェクトのクラスを参照する

  1. [プロパティ>Javaビルドパス]を開く
  2. [ライブラリ]タブを開く
  3. [クラスフォルダの追加]をクリックして、参照したいクラスのフォルダを指定する。

B. サーバーへのデプロイとリビルド

  1. [プロパティ>Java EE Module Dependencies]を開く
  2. サーバーへデプロイしたいクラスやjarを選択する

jarはどうも上手くいかないような気がしますが・・・
ともあれ助かったー

プログラミング

jsp:useBeanでジェネリックスを使う場合、classとtypeを両方指定する

Published by:

タイトルで言い切ってしまいましたが。

次のように書いたJSPコードをTomcat5.5で動かすと、「useBeanのクラス属性 java.util.ArrayList<ProductBean> の値が無効です」というエラーが出ました。

元コード
<jsp:useBean id="productList" class="java.util.ArrayList<ProductBean>" scope="request" />

ジェネリックスの型指定が気に入らないそうですが、そんな事言われてもあんたJava5でしょ?と言いたくなります。

ちなみにProductBeanクラスには引数なしのデフォルトコンストラクタが存在しますので、インスタンス化の失敗というわけではありません(引数なしのデフォルトコンストラクタのないクラスをclass属性でjsp:useBeanすると、同じようなエラーが出ます)。

そもそもインスタンスを作っているのはArrayListですので、 ProductBeanクラスに非はありません。
試しに「java.util.ArrayList<java.lang.String>」としても同じエラーが出ました。

対応策として、class属性の代わりにtype属性を指定するというものがあります。

対応策1
<jsp:useBean id="productList" type="java.util.ArrayList<ProductBean>" scope="request" />

これで上のエラーは出なくなりますが、これだとリクエストスコープに指定されたアトリビュートがセットされていない場合、「java.lang.InstantiationException: bean productList not found within scope」という別の例外になります。

必ず値がセットされているということであれば対応策1で良いのですが、そうではない場合対応策2になります。

対応策2
<jsp:useBean id="productList" class="java.util.ArrayList" type="java.util.ArrayList<ProductBean>" scope="request" />

「まさかなあ」という気持ちでこうしてみたら、これは動く。

JSPのバージョンのせいなのか、Tomcat5.5のバグなのか、はたまたこういう仕様なのか。
Tomcat6では未確認ですが、何ともおかしな振る舞いです。

CMS プログラミング

WordPress2.7で長すぎる投稿が表示されない不具合の原因と対策

Published by:

shortcodes
このドイツ語のブログでやっと原因と修正方法が分かりました。
几帳面にも、問題の正規表現の図解で解説までつけてくれたドイツ人に感謝。
それにつけても、やっぱりドイツ人てすげぇ・・・

 現象

そもそもの問題の現象ですが、WordPress2.7で長めの投稿をすると、何も表示されなくなるということが起こりました。
最初はプラグインを疑って利用停止したりしたのですが、それでも改善しません。

WordPressにはデフォルトでいくつかのフィルター(記事の内容に対して行われるコンテンツの更新機能)がありますが、途中のフィルターまではちゃんと動作している。
一つずつ確認していったところ、wpautopフィルターでコンテンツが削除されていることが分かりました。

wpautopフィルターの問題箇所を探していくと、下記の最終行で削除されています。

wpautop関数:
$pee = preg_replace('/<p>s*?(' . get_shortcode_regex() . ')s*</p>/s', '$1', $pee); // don't auto-p wrap shortcodes that stand alone

ここまできてGoogleで検索して確認しましたが、WordPress2.5.1のときからこの行に関しては問題を起こしていたようで、対応としてはコメントアウトする(臭いものにふたをする)というものばかり。

・・・で、件のブログを見つけました。

原因

ドイツ語ブログで書かれているとおり、本当の問題はショートコード(画像のキャプションなどを[caption] ~[/caption]のように記述する記法)用の正規表現を定義したget_shortcode_regex関数(wp-includes/shortcodes.php)にありました。

get_shortcode_regex関数(修正前):
return '[('.$tagregexp.')b(.*?)(?:(/)?](?:(.+?)[/1])?';

wpautop関数もそうですが、get_shortcode_regex関数もほとんどプログラム効率無視なコードになっていて、貪欲な正規表現によってpreg_replace関数が悲鳴を上げたのが原因のようでした。

対策

対策は、問題のget_shortcode_regex関数内のコードを修正すること。

get_shortcode_regex関数(修正後):
return '[('.$tagregexp.')b([^]]*?)(/)?](?:(.+?)[/1])?';

おおおっ!動いた~(T  T
プログラミングに国境なし、を改めて感じました。

#追記
次のバージョンで修正が消されるといやなので、WordPressサイトにバグ報告しました。
#再追記
と思ったら、http://trac.wordpress.org/ticket/8553とduplicateでしたorz
#2009/2/14 追記
WordPress2.7.1で直ってなかったので、自動アップグレードで元に戻ってしまった。
ぐはあ。