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


95

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

3
:이 사람 페이지에서 첫 번째 의견은 도움이 될 수 php.net/manual/en/function.base-convert.php#96304
세르게이 Eremin

와! 이것은 짧은 구현입니다. 감사합니다!
Cristian

PHP에서 Excel 문서를 생성하기 위해 기존 라이브러리를 살펴 보셨습니까?
Mark Baker

네 ... 물론입니다. 당신의 멋진 라이브러리를 사용하고 있습니다, Mark. 저는 알고리즘 작성 기술을 향상시키고 싶습니다. 좋은 점은 하나를 마친 후에 똑같은 기능을하지만 더 짧은 다른 알고리즘을 찾을 수 있다는 것입니다.
Cristian

2
짧은 알고리즘은 요청에서 0-> A를 사용합니다. 요청과 약간 다릅니다. 원하는 경우 PHPExcel의 PHPExcel_Cell :: stringFromColumnIndex () 메서드를 살펴보십시오. num2alpha () 구현은 나는 몇 가지 테스트를 실행거야 ... 빨리, 그리고 할 수있다 "차용"그것 (권한)
마크 베이커

답변:


155

다음은 멋지고 간단한 재귀 함수입니다 (인덱싱 된 숫자 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까지의 숫자로 테스트되었습니다 ...


감사! 시간당 1/2 씩 구해 줬어요!
Darryl Hein 2011

이 PHP 스크립트를 JS로 번역했습니다. gist.github.com/terox/161db6259e8ddb56dd77
terox

반향 기능이 좋은지 루프에서 사용하면 안 될까요? 스택 공간 문제가 발생할 수 있습니까?
Scott Chu

92

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

12
stringFromColumnIndex (1)은 'B'를 반환합니다
Ulterior

1
우수한! PHPExcel을 사용합니다. 이것은 깔끔한 대답입니다.
Scott Chu

PHPExcel_Cell::stringFromColumnIndex(1)실제로 반환 'B'됩니다. 답변을 수정하십시오.
MarthyM

13

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의 규칙을 따른다는 사실을 이용합니다. 문자 변수는 증가 할 수 있지만 감소 할 수는 없습니다.


그것은 좋은 솔루션입니다하지만 난 그것을 1234567789. 같은 큰 숫자에서 서버를 시간이 초과 생각
타히르 라자에게

5

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

이것은 반환 B을 위해 $number = 1대신 A때문에 1 % 26IS1
잘랄

5

늦은 답변이지만 여기에 내가 한 일이 있습니다 (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;
}

3

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

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

좋은 시도! 그래도 실패 할 것입니다 ... 2049 년에 시도해 보면 다음과 같이 표시됩니다. D
Cristian

2

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

    function getNameFromNumber ($ num, $ index = 0) {
        $ index = abs ($ index * 1); // 인덱스가 양의 정수인지 확인
        $ 숫자 = ($ num-$ index) % 26; 
        $ letter = chr (65 + $ numeric);
        $ num2 = intval (($ num-$ index) / 26);
        if ($ num2> 0) {
            getNameFromNumber ($ num2-1 + $ index)를 반환합니다. $ letter;
        } else {
            return $ letter;
        }
    }

기본 인덱싱을 0 기반으로 사용하고 있지만 PHP에서 배열로 저글링 할 때 양의 정수가 될 수 있습니다.


2

읽을 수 없기 때문에 프로덕션에서 사용하지 않을 것입니다.하지만 재미로 ... ZZ까지만합니다.

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

0

찾는 사람에게 자바 스크립트 이의 구현, 여기 @ ircmaxell의 대답자바 스크립트 ..

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;
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.