将整数转换为字母,反之亦然(例如,0 =“A”,26 =“AA”,27 =“AB”)

42

我有这个函数:

function toAlpha($data){
    $alphabet =   array('a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z');
    $alpha_flip = array_flip($alphabet);
    if($data <= 25){
      return $alphabet[$data];
    }
    elseif($data > 25){
      $dividend = ($data + 1);
      $alpha = '';
      $modulo;
      while ($dividend > 0){
        $modulo = ($dividend - 1) % 26;
        $alpha = $alphabet[$modulo] . $alpha;
        $dividend = floor((($dividend - $modulo) / 26));
      } 
      return $alpha;
    }
}

给定一个数字,将其转换为字符并且它运行得很好。

但是我还想要一个这样的反转函数:给定该函数的任何输出,返回确切的输入,以产生该输出。我尝试过以下代码:

function toNum($data){
$alphabet =   array('a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z');
    $alpha_flip = array_flip($alphabet);
  if(strlen($data) == 1){
          return (isset($alpha_flip[$data]) ? $alpha_flip[$data] : FALSE);
        }
        else if(strlen($data) > 1){
          $num = 1;
          for($i = 0; $i < strlen($data); $i++){
            if(($i + 1) < strlen($data)){
              $num *= (26 * ($alpha_flip[$data[$i]] + 1));
            }
            else{
              $num += ($alpha_flip[$data[$i]] + 1);
            }
          }
          return ($num + 25);
        }
}

但它没有正常工作...toAlpha(728)产生的是'aba',但toNum('aba')产生的是1378而不是728...

我做错了什么?如何修复反转函数使其正常工作?


所以你想把一个十进制数转换成二十六进制,是吗? - Mathieu Dumoulin
2
原始的toAlpha函数应该做什么?如果数字超过25,期望的行为是什么? - Alex Turpin
如果'a'是你的0,那么aa也应该是0吧?至少,如果你只是想使用字母而不是数字来实现纯粹的26进制。 - Hammerite
这两个函数期望得到的结果非常不清楚。你能解释一下这两个函数应该输出什么,以及根据什么规则来输出吗? - Decent Dabbler
在一般情况下,我认为最好的解决方案是使用chr()ord(),例如 $c = chr(ord('a') - 1 + $n); - 你甚至可以将ord('a') - 1(或ord('A')等)提取为常量。 - user719662
显示剩余2条评论
12个回答

157

最短的方式,在 PHP >= 4.1.0 版本中可用

$alphabet = range('A', 'Z');

echo $alphabet[3]; // returns D

echo array_search('D', $alphabet); // returns 3

1
这将无法处理超过字母表数组长度的任何整数;例如:"42"。 - kirgy
@kirgy,我根据这个情况发布了一个答案,可以处理超过字母表数组长度的整数。 - rvbarreto
1
对于字母 A,它将打印出 "0" 数字,这是错误的,因此新代码应该是:echo array_search($letter, $alphabet)+1; - Bbbb
1
对于一个字母,它将打印“0”数字,这是错误的,所以新代码应该是:echo array_search($letter, $alphabet) + 1; - Bbbb
1
自从问题发布以来,这一直是错误问题的正确答案。此页面上的答案得分向研究人员传达了不适当的信息。该答案不应该有积极的评分,因为它没有满足要求。 - mickmackusa

17

我完全不理解你在那个函数中尝试使用的逻辑。你所尝试做的事情似乎非常奇怪(为什么'a'映射到零,而'aa'映射到26?),但这似乎是有效的。(你需要使用更多的测试用例,我只检查了它是否能正确输出'aba'的情况。)

function toNum($data) {
    $alphabet = array( 'a', 'b', 'c', 'd', 'e',
                       'f', 'g', 'h', 'i', 'j',
                       'k', 'l', 'm', 'n', 'o',
                       'p', 'q', 'r', 's', 't',
                       'u', 'v', 'w', 'x', 'y',
                       'z'
                       );
    $alpha_flip = array_flip($alphabet);
    $return_value = -1;
    $length = strlen($data);
    for ($i = 0; $i < $length; $i++) {
        $return_value +=
            ($alpha_flip[$data[$i]] + 1) * pow(26, ($length - $i - 1));
    }
    return $return_value;
}

2
在十进制中,9的后继不是00。那么为什么aa是z的后继呢? - Hammerite
7
Excel可以做到这一点。也许@pillarOfLight正在尝试使用电子表格来解决某些问题。 - Stephane
33
$alphabet = range('a', 'z'); - wesside
@Hammerite 让我感到困惑,但在第二个 a 的单个字符之后,aa 移动到了 base 27,因为它具有位置价值(所以 a-z 加上没有 a = 27 个字符)。就像 001 101 一样! - BeNice
愚蠢的问题时间。1)为什么需要 $alpha_flip = array_flip($alphabet);,而原始代码中有一行 $modulo;。两者似乎都是多余的。2)我之前已经问过了,但在这里重复一遍:百分号(%)是什么意思?(我已经尝试过使用 Google、PHP.net、SO 等搜索引擎,但使用“%”进行搜索相当有趣。) - BeNice

16

PHP的 base_convert 函数的评论中,Theriault提出了一个非常聪明的解决方案。

/**
* Converts an integer into the alphabet base (A-Z).
*
* @param int $n This is the number to convert.
* @return string The converted number.
* @author Theriault
* 
*/
function num2alpha($n) {
    $r = '';
    for ($i = 1; $n >= 0 && $i < 10; $i++) {
    $r = chr(0x41 + ($n % pow(26, $i) / pow(26, $i - 1))) . $r;
    $n -= pow(26, $i);
    }
    return $r;
}
/**
* Converts an alphabetic string into an integer.
*
* @param int $n This is the number to convert.
* @return string The converted number.
* @author Theriault
* 
*/
function alpha2num($a) {
    $r = 0;
    $l = strlen($a);
    for ($i = 0; $i < $l; $i++) {
    $r += pow(26, $i) * (ord($a[$l - $i - 1]) - 0x40);
    }
    return $r - 1;
}

适用于任何数字:num2alpha(25) → "Z",num2alpha(26) → "AA",... - Philipp
1
提示:使用97代替0x41,使用96代替0x40以获得小写字母。或者使用strtolower()将结果转换为小写。 - Philipp

8

从数字到字母(以A=0,B=1等方式):

function toAlpha($num){
    return chr(substr("000".($num+65),-3));
}

你可以使用ord()函数将字母转换为相应的数字。
通过将65更改为97,您可以获得小写的值。

可以使用 chr(str_pad((65 + $num), 3, '0', STR_PAD_LEFT)) 替代 substr 调用。 - Othyn
关于这个的一个注意事项:它只适用于数字0-25(a-z)。toAlpha(26)返回{(在使用小写字母的基数97时)- 如果您始终期望一个1个字符的字母,请使用此选项。 - Philipp

5

使用Cyril的答案,我对多个字母的情况进行了详细解释。

function lettersToNumber($letters){
    $alphabet = range('A', 'Z');
    $number = 0;

    foreach(str_split(strrev($letters)) as $key=>$char){
        $number = $number + (array_search($char,$alphabet)+1)*pow(count($alphabet),$key);
    }
    return $number;
}

以下是该函数的一些结果:
lettersToNumber("A"); //returns 1
lettersToNumber("E"); //returns 5
lettersToNumber("Z"); //returns 26
lettersToNumber("AB"); //returns 28
lettersToNumber("AP"); //returns 42
lettersToNumber("CE"); //returns 83

5
你的问题来自于你的地图。看一下这个:
$alpha[0] = 'Alphabet';
for ($i = 'a'; $i<'z'; $i++) {
    $alpha[] = $i;
}
$alpha[26] = 'z';

你可以将其运行至服务器内存允许的最高值。PHP存在缺陷,如果使用小于等于 (<=) 运算符,在我的服务器上会出现问题:
$alpha[0] = 'Alphabet';
for ($i = 'a'; $i<='z'; $i++) {
    $alpha[] = $i;
}

然后它将一直映射到[676]=> string(2) "yz"!你只需要玩弄它。

我不想将一个字母映射到[0],所以我在那里放了一个标题。显然,如果您想要0=>a,1=>b等,可以将其省略。

一旦数组正确,函数就很简单。


1
one line : range('a', 'z') - ceadreak
@ceadreak 那个范围将不包括从 aa 开始的任何内容。 - mickmackusa

4
将数字转换为字母编码 例如:1402 to bax
function number_to_alpha($num, $code)
{   
    $alphabets = array('', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z');

    $division = floor($num / 26);
    $remainder = $num % 26; 

    if($remainder == 0)
    {
        $division = $division - 1;
        $code .= 'z';
    }
    else
        $code .= $alphabets[$remainder];

    if($division > 26)
        return number_to_alpha($division, $code);   
    else
        $code .= $alphabets[$division];     

    return strrev($code);
}

将字母编码转换为数字
例如:将 bax 转换为 1402
function alpha_to_number($code)
{
    $alphabets = array('', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z');

    $sumval = 0;

    $code = strtolower(trim($code));

    $arr = str_split($code);
    $arr_length = count($arr);

    for($i = 0, $j = $arr_length-1; $i < $arr_length; $i++, $j--)
    {
        $arr_value = array_search($arr[$i], $alphabets);
        $sumval = $sumval + ($arr_value * pow(26, $j));
    }

    return $sumval;
}

2
我拿到了“校正后”的原始代码,删除了调试代码和其他不必要的代码,并修改它使其适用于任意数量的字符。例如,希腊语只有24个字符。
function toAlpha($number, $alphabet)
    {

        $count = count($alphabet);
        if ($number <= $count) {
            return $alphabet[$number - 1];
        }
        $alpha = '';
        while ($number > 0) {
            $modulo = ($number - 1) % $count;
            $alpha  = $alphabet[$modulo] . $alpha;
            $number = floor((($number - $modulo) / $count));
        }
        return $alpha;
    }

    toAlpha(45,range('a','z'));

这里是一些范围的示例:

// lower greek
$range = ['α', 'β', 'γ', 'δ', 'ε', 'ζ', 'η', 'θ', 'ι', 'κ', 'λ', 'μ', 'ν', 'ξ', 'ο', 'π', 'ρ', 'σ', 'τ', 'υ', 'φ', 'χ', 'ψ', 'ω'];
// upper greek 
$range = ['Α', 'Β', 'Γ', 'Δ', 'Ε', 'Ζ', 'Η', 'Θ', 'Ι', 'Κ', 'Λ', 'Μ', 'Ν', 'Ξ', 'Ο', 'Π', 'Ρ', 'Σ', 'Τ', 'Υ', 'Φ', 'Χ', 'Ψ', 'Ω'];
// georgian 
$range = ['ჵ' => 10000, 'ჰ' => 9000, 'ჯ' => 8000, 'ჴ' => 7000, 'ხ' => 6000, 'ჭ' => 5000, 'წ' => 4000, 'ძ' => 3000, 'ც' => 2000, 'ჩ' => 1000, 'შ' => 900, 'ყ' => 800, 'ღ' => 700, 'ქ' => 600, 'ფ' => 500, 'ჳ' => 400, 'ტ' => 300, 'ს' => 200, 'რ' => 100, 'ჟ' => 90, 'პ' => 80, 'ო' => 70, 'ჲ' => 60, 'ნ' => 50, 'მ' => 40, 'ლ' => 30, 'კ' => 20, 'ი' => 10, 'თ' => 9, 'ჱ' => 8, 'ზ' => 7, 'ვ' => 6, 'ე' => 5, 'დ' => 4, 'გ' => 3, 'ბ' => 2, 'ა' => 1];

愚蠢的问题,为什么不是$number;而是$number--;。如果这个有效,它看起来就是我需要的。还有,什么是% LATER?不幸的是,这不能运行。$alpha = $alphabet[$modulo].$alpha;中的$alpha未定义。原始代码中有$alpha = " ",但即使插入了这个,它仍然无法工作。我没有意识到OP已经提供了一个可用的脚本。我浪费了20分钟尝试让它工作,所以,遗憾地,你得到了我的第一个负评。如果你修复了它,我会删除这个负评。 - BeNice
@BeNice 我刚刚运行了这段代码。示例可以正常工作,但你是对的,数字的起始点存在问题。还有一个 PHP 注意事项被抛出,但这不会影响其运行。 - Dr. Sassafras
@BeNice 我已经更新了例子,使用了我最终采用的方法。 - Dr. Sassafras
谢谢,我调整了另一个版本,并像往常一样拼凑出了一个解决方案(它能工作,但我不知道为什么它能工作!)请问您能否解释一下 --% 是什么意思? - BeNice
1
@BeNice http://php.net/manual/zh/language.operators.increment.php http://php.net/manual/zh/language.operators.arithmetic.php - Dr. Sassafras
谢谢。如果PHP.net能够拦截像“什么是%”这样的查询,那就太好了。虽然不是什么高深的技术,但如果不知道如何查找...我就找不到了。非常感谢。哦天啊 -- - 我已经使用了 ++ 一百次了。年龄慢慢地把我的大脑变成了糊状物。至于 % 是模运算,对于我们这些兼职工作者来说,我更喜欢清晰明了而不是简洁明了,但正如我所说,我只是一个兼职工作者。 - BeNice

0

这里是修复原始函数toAlpha的方法。它无法处理toAlpha(27)。

function toAlpha($n,$case = 'upper'){
    $alphabet   = array('A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z');
    $n = $n-1;
    Util::error_log('N'.$n);
    if($n <= 26){
        $alpha =  $alphabet[$n-1];
    } elseif($n > 26) {
        $dividend   = ($n);
        $alpha      = '';
        $modulo;
        while($dividend > 0){
            $modulo     = ($dividend - 1) % 26;
            $alpha      = $alphabet[$modulo].$alpha;
            $dividend   = floor((($dividend - $modulo) / 26));
        }
    }

    if($case=='lower'){
        $alpha = strtolower($alpha);
    }
    Util::error_log("**************".$alpha);
    return $alpha;

}

0

我们可以使用base_convert()函数将十进制(基数10)转换为字母数字(基数36),并将数字块的位置移动到字母块:

function toLetter(int $num) {
    return strtoupper(base_convert($num + 9, 10, 36));
}

1
问题要求将728转换为aba,但是这个答案却产生了KH。https://3v4l.org/77DNT 这是对错误问题的正确答案。 - mickmackusa
问题要求将 728 转换为 aba,但是这个答案却产生了 KH。https://3v4l.org/77DNT 这是对错误问题的正确回答。 - mickmackusa
1
该死,你是对的 ‍♂️ - shaedrich

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接