web-dev-qa-db-ja.com

ワークシートの列数をExcel文字(「AB」)ではなく整数(28)として取得する方法は?

与えられた:

$this->objPHPExcelReader = PHPExcel_IOFactory::createReaderForFile($this->config['file']);
$this->objPHPExcelReader->setLoadSheetsOnly(array($this->config['worksheet']));
$this->objPHPExcelReader->setReadDataOnly(true);
$this->objPHPExcel = $this->objPHPExcelReader->load($this->config['file']);

このように行を繰り返し処理できますが、非常に遅いです。つまり、"EL"列を持つワークシートを含む3MBのExcelファイルでは、約行ごとに1秒

foreach ($this->objPHPExcel->setActiveSheetIndex(0)->getRowIterator() as $row)
{
    $dataset = array();
    $cellIterator = $row->getCellIterator();
    $cellIterator->setIterateOnlyExistingCells(false);
    foreach ($cellIterator as $cell)
    {
        if (!is_null($cell))
        {
            $dataset[] = $cell->getCalculatedValue();
        }
    }
    $this->datasets[] = $dataset;
}

このように反復すると、かなり高速になります(30秒で約2000行)が、文字を変換する必要があります。 「EL」から数字へ:

$highestColumm = $this->objPHPExcel->setActiveSheetIndex(0)->getHighestColumn(); // e.g. "EL"
$highestRow = $this->objPHPExcel->setActiveSheetIndex(0)->getHighestRow();

$number_of_columns = 150; // TODO: figure out how to get the number of cols as int
for ($row = 1; $row < $highestRow + 1; $row++) {
    $dataset = array();
    for ($column = 0; $column < $number_of_columns; $column++) {
        $dataset[] = $this->objPHPExcel->setActiveSheetIndex(0)->getCellByColumnAndRow($column, $row)->getValue();
    }
    $this->datasets[] = $dataset;
}

Excelスタイルの文字(例: "AB")の代わりに整数(例: "28")として最上位の列を取得する方法はありますか?

32
Edward Tanguay
$colNumber = PHPExcel_Cell::columnIndexFromString($colString);

「A」の$ colStringから1、「Z」から26、「AA」から27などを返します。

そして(ほぼ)逆

$colString = PHPExcel_Cell::stringFromColumnIndex($colNumber);

0の$ colNumberから「A」、25から「Z」、26から「AA」などを返します。

[〜#〜] edit [〜#〜]

いくつかの便利なトリック:

ワークシートクラスにはtoArray()メソッドがあります。

$this->datasets = $this->objPHPExcel->setActiveSheetIndex(0)->toArray();

以下のパラメーターを受け入れます。

* @param  mixed    $nullValue          Value returned in the array entry if a cell doesn't exist
* @param  boolean  $calculateFormulas  Should formulas be calculated?
* @param  boolean  $formatData         Should formatting be applied to cell values?
* @param  boolean  $returnCellRef      False - Return a simple array of rows and columns indexed by number counting from zero
*                                      True - Return rows and columns indexed by their actual row and column IDs

イテレータを使用しますが、少し遅くなります

OR

Perlスタイルの文字列を増やす のPHPの機能を利用する

$highestColumm = $this->objPHPExcel->setActiveSheetIndex(0)->getHighestColumn(); // e.g. "EL" 
$highestRow = $this->objPHPExcel->setActiveSheetIndex(0)->getHighestRow();  

$highestColumm++;
for ($row = 1; $row < $highestRow + 1; $row++) {     
    $dataset = array();     
    for ($column = 'A'; $column != $highestColumm; $column++) {
        $dataset[] = $this->objPHPExcel->setActiveSheetIndex(0)->getCell($column . $row)->getValue();
    }
    $this->datasets[] = $dataset;
}

大量の行を処理している場合、実際には++ $ rowが$ row ++よりもパフォーマンスが向上していることに気付くかもしれません

72
Mark Baker

Excelを配列に変換し、空の要素から削除してから列数をカウントすることをお勧めします。

protected function getColumnsCheck($file, $col_number) {
        if (strstr($file, ".xls") != false && strstr($file, ".xlsx") != false) {
            $fileType = PHPExcel_IOFactory::identify($file);
            $objReader = PHPExcel_IOFactory::createReader($fileType);
            $objPHPExcel = $objReader->load($file);
            $columns_empty = $objPHPExcel->getActiveSheet(0)->toArray()[0]; 

            $columns = array_filter($columns_empty);

            return ($col_number==count($columns));
        }
        return false;
    }
1

最も簡単な解決策は$ getColumnIndexFromString = PHPExcel_Cell :: columnIndexFromString($ highestColumn);

1
Dinesh

これは、dqhendricksの回答を多少簡略化したものです。コピーに追加しました。1つの関数は完全なExcelセル参照(つまり "AB12")を入力すると仮定し、もう1つは列参照(つまり "AB")だけを入力すると仮定します。どちらもゼロベースのインデックスを返します。

フルセル参照の入力

_function getIndex ($cell) {
    // Strip cell reference down to just letters
    $let = preg_replace('/[^A-Z]/', '', $cell);

    // Iterate through each letter, starting at the back to increment the value
    for ($num = 0, $i = 0; $let != ''; $let = substr($let, 0, -1), $i++)
        $num += (ord(substr($let, -1)) - 65) * pow(26, $i);

    return $num;
}
_

入力列参照のみ

_function getIndex ($let) {
    // Iterate through each letter, starting at the back to increment the value
    for ($num = 0, $i = 0; $let != ''; $let = substr($let, 0, -1), $i++)
        $num += (ord(substr($let, -1)) - 65) * pow(26, $i);

    return $num;
}
_

この関数は、列の値を増やすために、文字列の後ろから前に移動します。 ord()関数を使用して文字の数値を取得し、文字値を減算してローカル列の値を取得します。最後に、現在の26の累乗が乗算されます。

1
foochow

クラスに組み込みメソッドがあるかどうかはわかりませんが、列インデックス文字列の各文字に対して常にord()関数を使用できます。もちろん、「A」のベース値を減算し、文字列の右端からの各位置に26 ^ xを掛ける必要があります。何かのようなもの:

    $input_string = 'BC';
    $base_value = 64;
    $decimal_value = 26;
    $column_index = 0;
    for ($i = 0; $i < strlen($input_string); $i++) {
        $char_value = ord($input_string[$i]);
        $char_value -= $base_value;
        $char_value *= pow($decimal_value, (strlen($input_string) - ($i + 1)));
        $column_index += $char_value;
    }
    echo $column_index;

基本的に、これは 'BC'を(2 * 26 ^ 1)+(3 * 26 ^ 0)= 55に等しくします。

$ input_stringは列インデックス文字列、$ base_valueは 'A'から1を引いたord()値、$ decimal_valueはA0の値です。任意の数値列まで機能します。テスト済み。お役に立てれば。

1
dqhendricks
    function getNameFromNumber($num) {//(Example 0 = A, 1 = B)
$numeric = $num % 26;
$letter = chr(65 + $numeric);
$num2 = intval($num / 26);
if ($num2 > 0) {
    return getNameFromNumber($num2 - 1) . $letter;
} else {
    return $letter;
}
}

getNameFromNumber(0)// Aを返す

0
ISCI