web-dev-qa-db-fra.com

Algorithme pour obtenir le nom de colonne de type Excel ressemblant à Excel

Je travaille sur un script qui génère des documents Excel et je dois convertir un nombre en son nom de colonne équivalent. Par exemple:

1 => A
2 => B
27 => AA
28 => AB
14558 => UMX

J'ai déjà écrit un algorithme pour le faire, mais j'aimerais savoir s'il existe des moyens plus simples ou plus rapides de le faire:

function numberToColumnName($number){
    $abc = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    $abc_len = strlen($abc);

    $result_len = 1; // how much characters the column's name will have
    $pow = 0;
    while( ( $pow += pow($abc_len, $result_len) ) < $number ){
        $result_len++;
    }

    $result = "";
    $next = false;
    // add each character to the result...
    for($i = 1; $i<=$result_len; $i++){
        $index = ($number % $abc_len) - 1; // calculate the module

        // sometimes the index should be decreased by 1
        if( $next || $next = false ){
            $index--;
        }

        // this is the point that will be calculated in the next iteration
        $number = floor($number / strlen($abc));

        // if the index is negative, convert it to positive
        if( $next = ($index < 0) ) {
            $index = $abc_len + $index;
        }

        $result = $abc[$index].$result; // concatenate the letter
    }
    return $result;
}

Connaissez-vous une meilleure façon de le faire? Peut-être quelque chose pour le garder plus simple? ou une amélioration de la performance?

Modifier

l'implémentation d'ircmaxell fonctionne plutôt bien. Mais, je vais ajouter ce joli court:

function num2alpha($n)
{
    for($r = ""; $n >= 0; $n = intval($n / 26) - 1)
        $r = chr($n%26 + 0x41) . $r;
    return $r;
}
75
Cristian

Voici une belle fonction récursive simple (Basée sur zéro nombre indexé, ce qui signifie 0 == A, 1 == B, etc.) ...

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

Et si vous le voulez indexé (1 == A, etc):

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

Testé avec des nombres de 0 à 10000 ...

129
ircmaxell

Utilisation de PhpSpreadsheet (PHPExcel est obsolète)

// result = 'A'
\PhpOffice\PhpSpreadsheet\Cell\Coordinate::stringFromColumnIndex(1);

Note index 0 résultats dans 'Z'

https://phpspreadsheet.readthedocs.io/en/develop/


La réponse correcte (si vous utilisez la bibliothèque PHPExcel) est:

// result = 'A'
$columnLetter = PHPExcel_Cell::stringFromColumnIndex(0); // ZERO-based! 

et à l'envers:

// result = 1
$colIndex = PHPExcel_Cell::columnIndexFromString('A');
75
ksn135

Indexé pour 1 -> A, 2 -> B, etc.

function numToExcelAlpha($n) {
    $r = 'A';
    while ($n-- > 1) {
        $r++;
    }
    return $r;
}

Indexé pour 0 -> A, 1 -> B, etc.

function numToExcelAlpha($n) {
    $r = 'A';
    while ($n-- >= 1) {
        $r++;
    }
    return $r;
}

Profite du fait que PHP suit la convention de Perl lorsqu'il traite des opérations arithmétiques sur les variables de caractère et non sur les C. Notez que les variables de caractère peuvent être incrémentées mais pas décrémentées.

12
Mark Baker

Cela va faire la conversion (en supposant l'arithmétique entière), mais je suis d'accord avec les autres affiches; utilisez simplement base_convert

function numberToColumnName($number)
{
    $abc = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    $len = strlen($abc);

    $result = "";
    while ($number > 0) {
       $index  = $number % $len;
       $result = $abc[$index] . $result;
       $number = floor($number / $len);
    }

    return $result;
}
4
Lucas

Nombre converti en lettres de colonnes Excel:

/**
 * Number convert to Excel column letters
 * 
 * 1 = A
 * 2 = B
 * 3 = C
 * 27 = AA
 * 1234567789 = CYWOQRM
 * 
 * @link https://vector.cool/php-number-convert-to-Excel-column-letters-2
 * 
 * @param int  $num       欄數
 * @param bool $uppercase 大小寫
 * @return void
 */
function num_to_letters($n)
{
    $n -= 1;
    for ($r = ""; $n >= 0; $n = intval($n / 26) - 1)
        $r = chr($n % 26 + 0x41) . $r;
    return $r;
}

ex:

echo num_to_letters(1);          // A
echo num_to_letters(2);          // B
echo num_to_letters(3);          // C
echo num_to_letters(27);         // AA
echo num_to_letters(1234567789); // CYWOQRM

Les lettres des colonnes Excel sont converties en nombre:

/**
 * Excel column letters convert to Number
 *
 * A = 1
 * B = 2
 * C = 3
 * AA = 27
 * CYWOQRM = 1234567789
 * 
 * @link https://vector.cool/php-number-convert-to-Excel-column-letters-2
 * 
 * @param string $letters
 * @return mixed
 */
function letters_to_num($a)
{
    $l = strlen($a);
    $n = 0;
    for ($i = 0; $i < $l; $i++)
        $n = $n * 26 + ord($a[$i]) - 0x40;
    return $n;
}

ex:

echo letters_to_num('A');       // 1
echo letters_to_num('B');       // 2
echo letters_to_num('C');       // 3
echo letters_to_num('AA');      // 27
echo letters_to_num('CYWOQRM'); // 1234567789
2
Ann

Réponse tardive, mais voici ce que j'ai fait (pour 1 == indexé):

function num_to_letters($num, $uppercase = true) {
    $letters = '';
    while ($num > 0) {
        $code = ($num % 26 == 0) ? 26 : $num % 26;
        $letters .= chr($code + 64);
        $num = ($num - $code) / 26;
    }
    return ($uppercase) ? strtoupper(strrev($letters)) : strrev($letters);
}

Ensuite, si vous voulez convertir dans l'autre sens:

function letters_to_num($letters) {
    $num = 0;
    $arr = array_reverse(str_split($letters));

    for ($i = 0; $i < count($arr); $i++) {
        $num += (ord(strtolower($arr[$i])) - 96) * (pow(26,$i));
    }
    return $num;
}
2
Mike
<?php
function numberToColumnName($number){
    $abc = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    $abc_len = strlen($abc);

    $result = "";
    $tmp = $number;

    while($number > $abc_len) {
        $remainder = $number % $abc_len;
        $result = $abc[$remainder-1].$result;
        $number = floor($number / $abc_len);
    }
    return $abc[$number-1].$result;
}

echo numberToColumnName(1)."\n";
echo numberToColumnName(25)."\n";
echo numberToColumnName(26)."\n";
echo numberToColumnName(27)."\n";
echo numberToColumnName(28)."\n";
echo numberToColumnName(14558)."\n";
?>
1
corsiKa

En combinant la réponse récursive d'ircmaxell, j'ai celle-ci:


 fonction getNameFromNumber ($ num, $ index = 0) {
 $ index = abs ($ index * 1); // vérifie que index est un entier positif 
 $ numeric = ($ num - $ index)% 26; 
 $ lettre = chr (65 + $ numérique); 
 $ num2 = intval (($ num - $ index)/26); 
 si ($ num2> 0) {
 retourne getNameFromNumber ($ num2 - 1 + $ index). $ lettre; 
 } autre {
 return $ letter; 
 } 
 } 

J'utilise l'indexation par défaut comme étant basée sur 0, mais il peut s'agir d'un entier positif pour jongler avec des tableaux en PHP.

1
Charlie Affumigato

Je n'utiliserais jamais cela en production car ce n'est pas lisible, mais pour le plaisir ......... Ne fait que jusqu'à ZZ.

<?php
    $col = 55;
    print (($n = (int)(($col - 1) / 26)) ? chr($n + 64) : '') . chr((($col - 1) % 26) + 65);
?>
0
simesy