PHPExcelでの汎用セル読み取り

こんにちは、Habr!

職場では、PHPを使用してExcelドキュメントをインポートする必要があります。

このために、私はPHPExcelライブラリーを使用します。これは、今日非常に便利なツールです。

しかし、細胞からのデータの読み取りに関連するいくつかの「滑りやすい」問題があります。これをhabrachitateliに伝え、これらの問題を解決する関数を解析します。



1.セルのアドレス指定



Excelで作業するときにセルに対処する方法はいくつかあります。



最初の方法は静的セルの場合に便利で、2番目と3番目のループは便利です。



ただし、PHPExcelには、これらの方法のいずれかでセルを取得するための汎用関数はありません。別個の関数しかありません。 さて、この省略を修正してください:

public function getCellValue($cellOrCol, $row = null) { //column set by index if(is_numeric($cellOrCol)) { $cell = $this->activeSheet->getCellByColumnAndRow($cellOrCol, $row); } else { $lastChar = substr($cellOrCol, -1, 1); if(!is_numeric($lastChar)) { //column contains only letter, eg "A" $cellOrCol .= $row; } $cell = $this->activeSheet->getCell($cellOrCol); } $val = $cell->getValue(); return $val; }
      
      





私が引用するコード例には$ thisへのリンクがあることをすぐに予約します。 これらは、PHPExcelのラッパークラスのメソッドです。 この部分では、セルオブジェクトを取得する3つの方法がすべて実装されています。



2.セルの結合



結合されたセルを読み取ると、PHPExcelは最初のセルを除くすべてのセルに対して空の値を返します。

つまり 以下の画像では、B3とC3の値は空の行になります。







私はいつもこの振る舞いに不快感を覚えています。

結合されたセルに共通の値「mergedvalue」を返す方がはるかに便利です(そしてより論理的です!)。

これを行うには、値を要求するときに、シートのすべての結合された範囲を調べ、指定されたセルが範囲内にある場合、最初のものを返す必要があります。

 $this->mergedCellsRange = $this->activeSheet->getMergeCells(); foreach($this->mergedCellsRange as $currMergedRange) { if($cell->isInRange($currMergedRange)) { $currMergedCellsArray = PHPExcel_Cell::splitRange($currMergedRange); $cell = $this->activeSheet->getCell($currMergedCellsArray[0][0]); break; } }
      
      







3.日付



ご存じのとおり、Excelは日付を1900年1月1日からの日数として保存します。 したがって、上記のスクリーンショットでセルB2を読み取ると、無駄な41044が表示されます。しかし、良いニュースもあります。PHPExcelには、日付をphp形式に変換する便利な関数PHPExcel_Shared_Date :: ExcelToPHP()があります。

この関数を適切なタイミングで適用するだけです。

 $val = $cell->getValue(); if(PHPExcel_Shared_Date::isDateTime($cell)) { $val = date($format, PHPExcel_Shared_Date::ExcelToPHP($val)); }
      
      







4.フォーミュラ



ほとんどの場合、標準関数$ cell-> getValue()は式を正しく処理し、計算された値を返します。 ただし、数式が存在しないシートまたはExcelドキュメントを送信した人によってローカルに保存されているその他のファイルを参照する場合があります。 その後、 getValue()はエラー返しますが、Excelでは視覚的にシートの再カウントがなかった場合に正しい値を見ることができます。 実際には、ExcelはoldCalculatedValueを保存します 。これは、シートを再カウントしない場合に使用されます。 上の図では、これをセルB4で示しています。古い値が表示されていますが、その中のリンクは壊れています。

幸いにも、PHPExcelは古い数式値を保存する方法を知っています。 これは、 getValue()が機能せず、値ではなく式自体(最初の文字「=」)を返した場合に使用すると便利です。



 $val = $cell->getValue(); if((substr($val,0,1) === '=' ) && (strlen($val) > 1)){ $val = $cell->getOldCalculatedValue(); }
      
      







結果



その結果、セル値を普遍的に読み取ることができる関数を取得しました。

  public function getCellValue($cellOrCol, $row = null, $format = 'dmY') { //column set by index if(is_numeric($cellOrCol)) { $cell = $this->activeSheet->getCellByColumnAndRow($cellOrCol, $row); } else { $lastChar = substr($cellOrCol, -1, 1); if(!is_numeric($lastChar)) { //column contains only letter, eg "A" $cellOrCol .= $row; } $cell = $this->activeSheet->getCell($cellOrCol); } //try to find current coordinate in all merged cells ranges //if find -> get value from head cell foreach($this->mergedCellsRange as $currMergedRange){ if($cell->isInRange($currMergedRange)) { $currMergedCellsArray = PHPExcel_Cell::splitRange($currMergedRange); $cell = $this->activeSheet->getCell($currMergedCellsArray[0][0]); break; } } //simple value $val = $cell->getValue(); //date if(PHPExcel_Shared_Date::isDateTime($cell)) { $val = date($format, PHPExcel_Shared_Date::ExcelToPHP($val)); } //for incorrect formulas take old value if((substr($val,0,1) === '=' ) && (strlen($val) > 1)){ $val = $cell->getOldCalculatedValue(); } return $val; }
      
      







テスト



確認するために、スクリーンショットからexelを2つの方法で読み取ります。標準のgetValue( #1 )と上記の関数の使用( #2 ):







テスト#1:



テスト#2:



ご覧のとおり、2番目のケースではすべてが正しいと見なされました。



軟膏で飛ぶ



項目2、3、および4の使用は、 ReadDataOnly = falseモードでのみ機能することに注意することが重要です。 これは、ブックに関するすべてのメタ情報を読み取るときのデフォルトのPHPExcelモードです。 請求書、請求書などの標準的な小さな文書に適しています。

セル値のみが必要な場合、かさばるファイルにはReadDataOnly = trueを含める必要があります。 私の練習では、そのようなファイルにはフォーマットされたテーブルが含まれており、そのような機能は必要ありません。



PHPExcelで読み取りモードを設定するには、次のようにします。

 $objReader = PHPExcel_IOFactory::createReaderForFile($filename); $objReader->setReadDataOnly(false); $this->PHPExcel = $objReader->load($filename);
      
      





ご清聴ありがとうございました!



All Articles