使用数字作为输入获取字母

时间:2015-01-08 18:03:53

标签: perl

我正在使用一些字母编码,其中输入是返回相应字母的数字。考虑输入是3它返回C,其中5是E,依此类推。如果number大于26,则输出更改为AA,27,28-AB,29-AC

这是代码:

my $input = <>;
my @a = ("A".."B");
if($input <=26){
    my $num1 = $input-1;
    say $a[$num1];
 }
 elsif( $input <= 702 ){ 
    #702 for ZZ
    my $mod = $input % 26;
    my $div = $input / 26;
    my ($letter) = $div =~ /^(\d+)\./;
    my $num1 = $div - 1;
    my $num2 = $letter - 1;
    say $a[$num1]$a[$num2];

}else{
      # Here I stuck
      # how to code for three or more letter combination?

}

三个字母组合有什么建议吗?

更新:输入数字不能为零。

4 个答案:

答案 0 :(得分:7)

我写了一个完整的测试套件,因为我发现这很难做对。

你是从基数10转换到基数26,但是因为1是A而不是0,所以一切都转移到1.在过程的早期处理(即。$number--)消除了很多下游错误。

#!/usr/bin/env perl

use v5.12;
use strict;
use warnings;

use Test::More;

my %tests = (
    1   => "A",
    1.0 => "A",
    2   => "B",
    25  => "Y",
    26  => "Z",
    27  => "AA",
    52  => "AZ",
    54  => "BB",
    78  => "BZ",
    (26**2 + 26) => "ZZ",
    (26**2 + 26 + 1) => "AAA",
    (26**3 + 26**2 + 26) => "ZZZ",
    (26**3 + 26**2 + 26 + 1) => "AAAA",
);

for my $have (keys %tests) {
    my $want = $tests{$have};
    is to_letters($have), $want, "to_letters($have) -> $want";
}

for my $negative (0, -1, -100) {
    ok !eval { to_letters($negative) }, "negative input $negative";
    like $@, qr{^0 and less cannot be converted to letters};
}

for my $decimal (1.1, 2.001) {
    ok !eval { to_letters($decimal) }, "decimal input $decimal";
    like $@, qr{^Decimals cannot be converted to letters};
}

done_testing;

use Carp;

sub to_letters {
    my $number = shift;
    croak "0 and less cannot be converted to letters" if $number <= 0;
    croak "Decimals cannot be converted to letters" if int $number != $number;

    state $BASE = 26;
    state $CHAR_BASE = 65;

    my @letters;
    while( $number > 0 ) {
        $number--;  # A is 1, not 0
        my $shift = $number % $BASE;
        unshift @letters, chr( $CHAR_BASE + $shift );
        $number = int($number / $BASE);
    }

    return join '', @letters;
}

这些常数可能看似愚蠢,但它是21世纪,其他角色编码很有可能成为考虑因素。虽然我怀疑chr( $CHAR_BASE + $shift)会很好地解决问题。

答案 1 :(得分:3)

我想你想要一个while循环。不知道你在哪里得到351 - 我得到了#34; NN&#34;。 26 * 26 = 676。

E.g。类似的东西:

use warnings;
use strict;

my $number = 17577;
my @letters;

while ( $number > 0 ) {
  my $part = $number % 26; 
  #print "$part, $number\n";

  $number -= $part;

  if ( $number == 26 ) { $number = 0; }
  $number /= 26;
  #print "$number $part\n";
  push @letters,chr(65+$part);
}

print reverse @letters;

答案 2 :(得分:2)

我不太了解Perl以便在其中写下答案,但这里的算法可以适用于任何长度:

verify the input value is valid for your purpose
set Number to the input value (for clarity in this answer, or if you need the input value later)
set Output to an empty string
while Number > 25
   set Remainder to Number modulo 26 plus 1
   set Number to the integer part of Number divided by 26
   prepend the character represented by Remainder to Output
end while

if Number is not zero prepend the character represented by Number plus 1 to the Output

答案 3 :(得分:1)

Perl已经按字母顺序进行自动递增,因此实现所需内容的最短方法是在循环中利用它。

my $a = 'A';
my $n = $ARGV[0];
for (my $i = 1; $i < $n; $i++) { $a++ }
print $a;

当然,数字越大,循环越多,因此对于非常大的数字可能效率不高。