こぶたのラッパ » 2012 年 6 月 8 日

Daily Archives: 2012 年 6 月 8 日

プログラミング

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つです。

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