Thuật toán lấy tên cột giống excel của một số


95

Tôi đang làm việc trên một tập lệnh tạo một số tài liệu Excel và tôi cần chuyển một số thành tên cột tương đương của nó. Ví dụ:

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

Tôi đã viết một thuật toán để làm như vậy, nhưng tôi muốn biết liệu cách làm đơn giản hơn hay nhanh hơn:

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

Bạn có biết một cách tốt hơn để làm điều đó? Có lẽ một cái gì đó để giữ cho nó đơn giản hơn? hoặc cải thiện hiệu suất?

Biên tập

Việc triển khai của ircmaxell hoạt động khá tốt. Nhưng, tôi sẽ thêm đoạn ngắn hay này:

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

3
bình luận đầu tiên trong trang người đàn ông này có thể hữu ích: php.net/manual/en/function.base-convert.php#96304
Sergey Eremin

Chà! Đó là một triển khai ngắn. Cảm ơn bạn!
Cristian,

Bạn đã xem bất kỳ thư viện hiện có nào để tạo tài liệu Excel từ PHP chưa?
Mark Baker vào

Phải, tất nhiên. Tôi đang sử dụng thư viện tuyệt vời của bạn, Mark. Tôi chỉ muốn cải thiện kỹ năng viết thuật toán của mình ... điều hay là sau khi bạn hoàn thành một thuật toán, bạn có thể tìm thấy các thuật toán khác giống hệt như vậy nhưng ngắn hơn.
Cristian,

2
Thuật toán ngắn của bạn sử dụng 0 -> A thay vì 1 -> A trong yêu cầu của bạn, hơi khác so với yêu cầu ... nếu đó là điều bạn muốn, hãy xem phương thức PHPExcel_Cell :: stringFromColumnIndex () của PHPExcel, mặc dù việc triển khai num2alpha () của bạn có thể được nhanh hơn ... tôi sẽ chạy một số xét nghiệm, và có thể "mượn" nó (với sự cho phép)
Mark Baker

Câu trả lời:


155

Đây là một hàm đệ quy đơn giản tuyệt vời (Dựa trên số không được lập chỉ mục, nghĩa là 0 == A, 1 == B, v.v.) ...

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

Và nếu bạn muốn nó được lập chỉ mục (1 == A, v.v.):

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

Đã thử nghiệm với các số từ 0 đến 10000 ...


Cảm ơn! Đã tiết kiệm cho tôi 1/2 giờ!
Darryl Hein

Tôi đã dịch tập lệnh PHP này sang JS: gist.github.com/terox/161db6259e8ddb56dd77
terox

Tôi nghi ngờ nếu chức năng lặp lại là tốt hay không nếu được sử dụng trong một vòng lặp? Nó có thể gây ra vấn đề về không gian ngăn xếp?
Scott Chu,

90

Sử dụng PhpS Spreadsheet ( PHPExcel không được dùng nữa )

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

Lưu ý chỉ số 0 cho kết quả là 'Z'

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


Câu trả lời đúng (nếu bạn sử dụng Thư viện PHPExcel ) là:

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

và ngược lại:

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

12
stringFromColumnIndex (1) trả về 'B'
Ulterior 09/09

1
Thông minh! Tôi tình cờ sử dụng PHPExcel. Đây là câu trả lời gọn gàng.
Scott Chu

PHPExcel_Cell::stringFromColumnIndex(1)thực sự trở lại 'B', vui lòng chỉnh sửa câu trả lời của bạn.
MarthyM 22/09/17

13

Được lập chỉ mục cho 1 -> A, 2 -> B, v.v.

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

Được lập chỉ mục cho 0 -> A, 1 -> B, v.v.

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

Tận dụng lợi thế của thực tế là PHP tuân theo quy ước của Perl khi xử lý các phép toán số học trên các biến ký tự chứ không phải C. Lưu ý rằng các biến ký tự có thể tăng nhưng không giảm.


đó là một giải pháp tốt nhưng tôi nghĩ rằng nó sẽ hết thời gian chờ máy chủ với những số lượng lớn như 1234567789.
Tahir Raza

5

Điều này sẽ làm cho chuyển đổi (giả sử số học nguyên), nhưng tôi đồng ý với các áp phích khác; chỉ dùngbase_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;
}

Điều này sẽ quay trở lại Bđể $number = 1thay cho Atừ 1 % 261
Jalal

5

Câu trả lời muộn, nhưng đây là những gì tôi đã làm (cho 1 == A được lập chỉ mục):

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

Sau đó, nếu bạn muốn chuyển đổi theo cách khác:

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

Chuyển đổi số thành các ký tự cột trong 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;
}

Ví dụ:

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

Các ký tự cột trong Excel chuyển đổi thành Số:

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

Ví dụ:

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

Rất vui! Nó sẽ thất bại mặc dù ... cung cấp cho nó một thử với 2049 và bạn sẽ thấy: D
Cristian

2

Kết hợp câu trả lời đệ quy của ircmaxell, tôi có câu này:

    function getNameFromNumber ($ num, $ index = 0) {
        $ index = abs ($ index * 1); // đảm bảo rằng chỉ mục là một số nguyên dương
        $ numeric = ($ num - $ index)% 26; 
        $ letter = chr (65 + $ số);
        $ num2 = intval (($ num - $ index) / 26);
        nếu ($ num2> 0) {
            trả về getNameFromNumber ($ num2 - 1 + $ index). thư $;
        } khác {
            trả lại $ thư;
        }
    }

Tôi đang sử dụng lập chỉ mục mặc định là dựa trên 0, nhưng nó có thể là bất kỳ số nguyên dương nào khi kết hợp với các mảng trong PHP.


2

Tôi không bao giờ sử dụng nó trong sản xuất vì nó không thể đọc được, nhưng để giải trí ... Chỉ có tối đa ZZ.

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

0

Đối với bất kỳ ai đang tìm kiếm cách triển khai Javascript về điều này, đây là câu trả lời của @ ircmaxell trong 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;
    }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.