web-dev-qa-db-fra.com

php: convertir un nombre en alphabet et vice versa

J'ai donc cette fonction:

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

qui donne un numéro le convertit en caractère et cela fonctionne très bien

mais alors je veux aussi une fonction inverse de ce qui donne n'importe quelle sortie de cette fonction, renvoie l'entrée exacte qui a été mise pour produire cette sortie et j'ai essayé ceci:

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

mais cela ne fonctionne pas correctement ... toAlpha (728) produit 'aba' mais toNum ('aba') en produit 1378 plutôt que 728 ...

qu'ai-je fait de mal? Comment puis-je corriger la fonction inverse pour qu'elle fonctionne correctement?

merci d'avance!

19
pillarOfLight

Je ne comprends pas du tout la logique que vous essayez d'utiliser dans cette fonction. Ce que vous essayez de faire semble très étrange (pourquoi "une carte" à zéro et pourtant "un" correspond à 26?), Mais cela semble fonctionner. (Vous voudrez utiliser quelques cas de test supplémentaires, j'ai seulement vérifié que cela donne la sortie correcte pour le cas '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;
}
13
Hammerite

Chemin le plus court, dans PHP> = 4.1.0

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

echo $alphabet[3]; // returns D

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

De numéro en alphabet (avec A = 0, B = 1, etc ...):

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

Vous pouvez faire la même chose d'un alphabet à l'autre avec la fonction ord().

En modifiant 65 avec 97, vous pouvez obtenir les valeurs minuscules.

4
sara_thepot

Vos problèmes viennent de votre carte. Regarde ça:

$alpha[0] = 'Alphabet';
for ($i = 'a'; $i<'z'; $i++) {
    $alpha[] = $i;
}
$alpha[26] = 'z';

Vous pouvez l'exécuter aussi haut que vous le souhaitez et la mémoire de votre serveur vous le permettra. Le PHP est bogué, et (du moins sur mon serveur) si vous utilisez l'opérateur <=:

$alpha[0] = 'Alphabet';
for ($i = 'a'; $i<='z'; $i++) {
    $alpha[] = $i;
}

alors il mappera tout le chemin vers [676] => string (2) "yz"! Vous devez juste jouer avec. 

Je ne voulais pas mapper une lettre sur [0], alors je me suis contenté d'y insérer un titre. Évidemment, vous pouvez le laisser si vous voulez 0 => a, 1 => b, etc.

Une fois que le tableau est correct, la fonction est triviale.

4
Mason Barge

J'ai pris l'original «corrigé», supprimé le code de débogage et tout autre code inutile, je l'ai modifié pour qu'il fonctionne avec n'importe quel nombre de caractères. Par exemple, le grec n'a que 24 caractères.

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

Et voici quelques exemples de gammes:

// 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];
1
Dr. Sassafras
// to convert number to alphacode
// for ex 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);
 </ pre> 

} </ code>

// to convert alphacode to number
// for ex  bax to 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;
 </ pre> 

} </ code>

1
Praveen

Voici un correctif à la fonction originale toAlpha. Cela ne fonctionne pas pour 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
Santosh Pradhan