【问题标题】:php: converting number to alphabet and vice versaphp:将数字转换为字母,反之亦然
【发布时间】:2011-12-01 14:57:05
【问题描述】:

所以我有这个功能:

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...

我做错了什么?如何修复反向功能使其正常工作?

提前致谢!

【问题讨论】:

  • 所以你正在尝试将一个以 10 为底的数字转换为以 26 为底的数字,是这样吗?
  • 原来的 toAlpha 函数应该做什么?如果数字超过 25,期望的行为是什么?
  • 变成双字母、三字母等 eg: 26 = aa, 27 = ab, etc
  • 如果'a'是你的0,那么aa不应该也是0吗?至少,如果您只是尝试使用字母而不是数字来实现直接 base-26。
  • 这两个函数的期望结果真的不清楚。你能解释一下这些函数应该准确输出什么以及遵循什么规则吗?

标签: php string function math reverse


【解决方案1】:

我完全不明白您试图在该函数中使用的逻辑。你试图做的事情看起来很奇怪(为什么'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;
}

【讨论】:

  • 以10为底,9的后继不是00。那么为什么aa是z的后继呢?
  • Excel 执行此操作。也许@pillarOfLight 试图用电子表格找出一些东西。
  • $alphabet = range('a', 'z');
  • @Hammerite 让我感到困惑,但在单个字符之后,aa 中的第二个 a 将其从基数 26 移动到 base 27,因为它具有位置值(所以 az 加上没有a = 27 个字符)。好像001101!
  • 愚蠢的提问时间。 1) 为什么需要`$alpha_flip = array_flip($alphabet);` 并且在原文中有一行$modulo;。两者似乎都是多余的。 2)我在上面问过,但会在这里重复:% 是做什么的? (我尝试过 Goog、PHP.net、SO 等,但使用 % 进行搜索相当有趣。)
【解决方案2】:

您的问题来自您的地图。看看这个:

$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 等,你可以省略它。

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

【讨论】:

  • 一行:range('a', 'z')
【解决方案3】:
function toNum($str) {
  $num = 0;
  for ($i = 0; $i < strlen($str); $i++) {
    $num += ord($str[$i]);
    $num *= 26;
  }
  return $num;
}

function toStr($num) {
  $str = '';
  while ($num > 0) {
    $str = chr($num % 26) . $str;
    $num = (int) ($num / 26);
  }
  return $str;
} 

【讨论】:

  • 考虑添加一些评论
【解决方案4】:

这是对原始函数 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;

}

【讨论】:

    【解决方案5】:

    最短的方法,在 PHP >= 4.1.0

    $alphabet = range('A', 'Z');
    
    echo $alphabet[3]; // returns D
    
    echo array_search('D', $alphabet); // returns 3
    

    【讨论】:

    • 出色且省时的答案。
    • 这不适用于任何超过字母数组长度的整数;例如“42”。
    • @kirgy 我根据这种情况发布了一个答案,该答案适用于超过字母数组长度的整数。
    • 感谢您的简短回答。
    【解决方案6】:

    从数字到字母(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 调用
    • 关于这一点的一个注意事项:它只适用于数字 0 - 25 (a-z)。 toAlpha(26) 返回 {(当使用基数 97 表示小写时) - 如果您总是期望一个 1 个字符的字母,请使用它
    【解决方案7】:

    我采用了“更正”的原件,删除了调试代码和其他不必要的代码,并对其进行了修改,使其适用于任意数量的字符。例如,希腊语只有 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 我刚刚运行了代码。该示例运行良好,但您的权利在于数字的起点存在问题。还有一个PHP的提示是抛出的,不过这不影响它的运行。
    • @BeNice 我已将示例更新为我最终使用的内容。
    • 谢谢我调整了另一个版本,并像往常一样一起破解了一个解决方案(我不知道为什么,它有效,但它有效!)你能解释一下--%请。
    【解决方案8】:

    将数字转换为字母代码

    例如:1402 到 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;
    }
    

    【讨论】:

      【解决方案9】:

      使用西里尔的回答,我对一个有多个字母的情况进行了详细说明。

      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
      

      【讨论】:

        【解决方案10】:

        Theriault 在 PHPs base_convert function 的 cmets 中有一个非常聪明的解决方案

        /**
        * 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", ...
        • 提示:使用97 代替0x4196 代替0x40 来获取小写字母。或者使用strtolower()将结果转为小写
        【解决方案11】:

        这个怎么样?

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2022-01-07
          • 2011-05-27
          • 2021-11-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多