Programing

숫자의 Excel과 유사한 열 이름을 얻는 알고리즘

lottogame 2020. 9. 17. 18:48
반응형

숫자의 Excel과 유사한 열 이름을 얻는 알고리즘


일부 Excel 문서를 생성하는 스크립트를 작성 중이며 숫자를 해당 열 이름으로 변환해야합니다. 예를 들면 :

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

나는 이미 알고리즘을 작성했지만 더 간단하거나 빠른 방법인지 알고 싶습니다.

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

더 나은 방법을 알고 있습니까? 더 간단하게 유지해야할까요? 또는 성능 향상?

편집하다

ircmaxell의 구현은 꽤 잘 작동합니다. 하지만이 멋진 짧은 것을 추가 할 것입니다.

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

다음은 멋지고 간단한 재귀 함수입니다 (인덱싱 된 숫자 0을 기반으로 함, 0 == A, 1 == B 등을 의미 함) ...

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

인덱싱하려는 경우 (1 == A 등) :

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

0에서 10000까지의 숫자로 테스트되었습니다 ...


PhpSpreadsheet 사용 ( PHPExcel은 더 이상 사용되지 않음 )

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

참고 인덱스 0은 'Z'가됩니다.

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


정답 ( PHPExcel Library 를 사용하는 경우 )은 다음과 같습니다.

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

그리고 거꾸로 :

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

1-> A, 2-> B 등에 대해 인덱싱 됨

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

0-> A, 1-> B 등에 대해 인덱싱 됨

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

C가 아닌 문자 변수에 대한 산술 연산을 다룰 때 PHP가 Perl의 규칙을 따른다는 사실을 활용합니다. 문자 변수는 증가 할 수 있지만 감소 할 수는 없습니다.


이것은 변환 (정수 산술 가정)에 영향을 미치지 만 다른 포스터에 동의합니다. 그냥 사용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;
}

늦은 답변이지만 여기에 내가 한 일이 있습니다 (1 == A 인덱싱 됨).

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

그런 다음 다른 방식으로 변환하려는 경우 :

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

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

전의:

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 열 문자는 숫자로 변환됩니다.

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

전의:

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

<?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";
?>

ircmaxell의 재귀 답을 결합하면 다음과 같은 결과가 있습니다.


    function getNameFromNumber ($ num, $ index = 0) {
        $index = abs($index*1); //make sure index is a positive integer
        $numeric = ($num - $index) % 26; 
        $letter = chr(65 + $numeric);
        $num2 = intval(($num -$index) / 26);
        if ($num2 > 0) {
            return getNameFromNumber($num2 - 1 + $index) . $letter;
        } else {
            return $letter;
        }
    }

I'm using the default indexing as 0 based, but it can be any positive integer for when juggling with arrays in PHP.


I'd never use this in production because it's not readable, but for fun... Only does up to ZZ.

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

참고URL : https://stackoverflow.com/questions/3302857/algorithm-to-get-the-excel-like-column-name-of-a-number

반응형