Algorithmus zum Abrufen des Excel-ähnlichen Spaltennamens einer Zahl

95

Ich arbeite an einem Skript, das einige Excel-Dokumente generiert, und ich muss eine Zahl in den entsprechenden Spaltennamen konvertieren. Beispielsweise:

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

Ich habe bereits einen Algorithmus dafür geschrieben, möchte aber wissen, ob es einfachere oder schnellere Möglichkeiten gibt:

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;
}

Kennen Sie einen besseren Weg, dies zu tun? Vielleicht etwas, um es einfacher zu halten? oder eine Leistungsverbesserung?

Bearbeiten

Die Implementierung von ircmaxell funktioniert ziemlich gut. Aber ich werde diesen schönen kurzen hinzufügen:

function num2alpha($n)
{
    for($r = ""; $n >= 0; $n = intval($n / 26) - 1)
        $r = chr($n%26 + 0x41) . $r;
    return $r;
}
Cristian
quelle
3
Der erste Kommentar in dieser Manpage könnte hilfreich sein: php.net/manual/en/function.base-convert.php#96304
Sergey Eremin
Beeindruckend! Das ist eine kurze Implementierung. Danke dir!
Cristian
Haben Sie sich eine der vorhandenen Bibliotheken angesehen, um Excel-Dokumente aus PHP zu generieren?
Mark Baker
Ja natürlich. Ich benutze deine großartige Bibliothek, Mark. Ich möchte nur meine Fähigkeiten beim Schreiben von Algorithmen verbessern ... Das Schöne daran ist, dass Sie nach Abschluss eines Algorithmus andere Algorithmen finden können, die genau das Gleiche tun, aber kürzer sind.
Cristian
2
Ihr kurzer Algorithmus verwendet in Ihrer Anfrage 0 -> A anstelle von 1 -> A, was sich geringfügig von der Anfrage unterscheidet. Wenn Sie dies wünschen, sehen Sie sich die PHPExcel_Cell :: stringFromColumnIndex () -Methode von PHPExcel an, obwohl Ihre num2alpha () -Implementierung dies möglicherweise tut Sei schneller ... Ich werde einige Tests durchführen und kann sie (mit Erlaubnis) "ausleihen"
Mark Baker

Antworten:

155

Hier ist eine schöne einfache rekursive Funktion (basierend auf null indizierten Zahlen, was 0 == A, 1 == B usw. bedeutet) ...

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;
    }
}

Und wenn Sie möchten, dass es indiziert wird (1 == A usw.):

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;
    }
}

Getestet mit Zahlen von 0 bis 10000 ...

ircmaxell
quelle
Vielen Dank! Hat mir eine halbe Stunde gespart!
Darryl Hein
Ich habe dieses PHP-Skript in JS übersetzt: gist.github.com/terox/161db6259e8ddb56dd77
terox
Ich bezweifle, ob die Recusive-Funktion gut ist oder nicht, wenn sie in einer Schleife verwendet wird. Könnte dies zu Problemen mit dem Stapelspeicher führen?
Scott Chu
90

Verwenden von PhpSpreadsheet ( PHPExcel ist veraltet )

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

Hinweis Index 0 ergibt 'Z'

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


Die richtige Antwort (wenn Sie PHPExcel Library verwenden) lautet:

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

und rückwärts:

// result = 1
$colIndex = PHPExcel_Cell::columnIndexFromString('A');
ksn135
quelle
12
stringFromColumnIndex (1) gibt 'B'
Ulterior
1
Ausgezeichnet! Ich benutze zufällig PHPExcel. Das ist eine gute Antwort.
Scott Chu
PHPExcel_Cell::stringFromColumnIndex(1)in der Tat zurück 'B', bitte bearbeiten Sie Ihre Antwort.
MarthyM
13

Indiziert für 1 -> A, 2 -> B usw.

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

Indiziert für 0 -> A, 1 -> B usw.

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

Nutzt die Tatsache aus, dass PHP Perls Konvention folgt, wenn es um arithmetische Operationen mit Zeichenvariablen und nicht mit C geht. Beachten Sie, dass Zeichenvariablen inkrementiert, aber nicht dekrementiert werden können.

Mark Baker
quelle
Es ist eine gute Lösung, aber ich denke, es wird den Server bei großen Zahlen wie 1234567789 auslaufen lassen.
Tahir Raza
5

Dies reicht für die Konvertierung aus (unter der Annahme einer ganzzahligen Arithmetik), aber ich stimme den anderen Postern zu. benutz einfachbase_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;
}
Lucas
quelle
Dies wird wieder Bfür $number = 1statt , Ada 1 % 26heißt1
Jalal
5

Späte Antwort, aber hier ist, was ich getan habe (für 1 == A indiziert):

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);
}

Wenn Sie dann in die andere Richtung konvertieren möchten:

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;
}
Mike
quelle
3

Zahlenkonvertierung in Excel-Spaltenbuchstaben:

/**
 * 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

Excel-Spaltenbuchstaben werden in Zahlen konvertiert:

/**
 * 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
Ann
quelle
2
<?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";
?>
corsiKa
quelle
Netter Versuch! Es wird aber scheitern ... probieren Sie es mit 2049 und Sie werden sehen: D
Cristian
2

Wenn ich die rekursive Antwort von ircmaxell kombiniere, habe ich folgende:

    Funktion getNameFromNumber ($ num, $ index = 0) {
        $ index = abs ($ index * 1); // Stellen Sie sicher, dass der Index eine positive Ganzzahl ist
        $ numeric = ($ num - $ index)% 26; 
        $ letter = chr (65 + $ numerisch);
        $ num2 = intval (($ num - $ index) / 26);
        if ($ num2> 0) {
            return getNameFromNumber ($ num2 - 1 + $ index). $ letter;
        } else {
            $ letter zurückgeben;
        }}
    }}

Ich verwende die Standardindizierung als 0-basiert, aber es kann eine beliebige positive Ganzzahl sein, wenn Sie mit Arrays in PHP jonglieren.

Charlie Affumigato
quelle
2

Ich würde das nie in der Produktion verwenden, weil es nicht lesbar ist, aber zum Spaß ... Nur bis zu ZZ.

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

Für alle, die nach einer Javascript- Implementierung suchen , ist hier die Antwort von @ ircmaxell in Javascript .

function getNameFromNumber(num){
    let numeric = num%26;
    let letter = String.fromCharCode(65+numeric);
    let num2 = parseInt(num/26);
    if(num2 > 0) {
      return getNameFromNumber(num2 - 1)+letter;
    } else {
      return letter;
    }
}

Cels
quelle