Декодер азбуки Морзе на Perl

Я пытаюсь научить себя Perl, и я борюсь ... Прошлой ночью я написал программу для вычисления среднего набора чисел, предоставленных пользователем, чтобы узнать о списках и пользовательском вводе, поэтому сегодня я подумал, что сделаю декодер азбуки Морзе, чтобы узнать о хэшах. Я просмотрел книгу, которую купил, и она не очень хорошо объясняет хэши... на самом деле она не очень хорошо объясняет многие вещи. Любая помощь будет оценена по достоинству!

В любом случае, я хочу написать программу, которая декодирует код Морзе, который вводит пользователь. Таким образом, пользователь должен ввести:

-.-.
.-
-
...
!
.-.
..-
.-..
.

Восклицательный знак будет означать отдельное слово. Это сообщение вернет пользователю «Cats Rule». Ниже приведен код, который у меня есть... Помните... Я программирую на Perl менее 24 часов, ха-ха.

Код:

  use 5.010;




my %morsecode=(
    '.-'    =>'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',  '.----' =>'1',  '..---' =>'2',
    '...--' =>'3',  '....-' =>'4',  '.....' =>'5',  '-....' =>'6',
    '--...' =>'7',  '---..' =>'8',  '----.' =>'9',  '-----' =>'0',
    '.-.-.-'=>'.',  '--..--'=>',',  '---...'=>':',  '..--..'=>'?',
    '.----.'=>'\'', '-...-' =>'-',  '-..-.' =>'/',  '.-..-.'=>'\"'
);

my @k = keys %morsecode;
my @v = values %morsecode;

say "Enter a message in morse code separated by a line. Use the exclamation point (!) to separate words. Hit Control+D to signal the end of input.";
my @message = <STDIN>;
chomp @message;

my $decodedMessage = encode(@message);


sub encode {
    foreach @_ {
    if (@_ == @k) {
        return @k;

#This is where I am confused... I am going to have to add the values to an array, but I don't really know how to go about it.


        }
    else if(@_ == '!') {return ' '}
    else
    {
    return 'Input is not valid';
    }
    }
}

person JLott    schedule 25.01.2013    source источник
comment
Я бы посоветовал изучить tizag.com/perlT/perlarrays.php и tizag.com/perlT/perlhashes.php. Или любой другой учебник по массиву/хэшу, который вы найдете в Google по этому вопросу. Удачи.   -  person dutt    schedule 26.01.2013
comment
Спасибо! Я ценю это!   -  person JLott    schedule 26.01.2013
comment
Хорошие отправные точки: веб-сайт для изучения Perl, Книга по современному Perl, Learning Perl book, а также эта должна помочь с хэшами   -  person Craig Treptow    schedule 26.01.2013
comment
Кроме того, настоятельно рекомендуется использовать use warnings; и use strict; во всем коде, чтобы помочь выявить ошибки.   -  person Craig Treptow    schedule 26.01.2013
comment
Прежде чем делать что-либо еще, поместите use strict; и use warnings; в начало вашего скрипта. Они помогают, хотя сначала они вам, вероятно, не понравятся. Кстати, достойный выбор 1-го проекта для изучения хэшей.   -  person William    schedule 26.01.2013
comment
@k и @v бессмысленны. Также ваш сабвуфер должен называться decode, а не encode.   -  person Brad Gilbert    schedule 26.01.2013
comment
Спасибо всем вам за вашу помощь! Это действительно помогло в изучении многих полезных основ.   -  person JLott    schedule 26.01.2013


Ответы (3)


Ваш код содержит две синтаксические ошибки: foreach требуется список для повторения; это означает паренс. В отличие от C и других языков, Perl не поддерживает else if (...). Вместо этого используйте elsif (...).

Затем есть несколько семантических ошибок: Текущее значение итерации хранится в $_. Массив @_ содержит аргументы вызова вашей функции.

Perl сравнивает строки и числа по-разному:

Strings Numbers
eq      ==
lt      <
gt      >
le      <=
ge      >=
ne      !=
cmp     <=>

Используйте правильные операторы для поставленной задачи, в данном случае — строгие.

(Ваш код @_ == @k что-то делает, а именно использует массивы в числовом контексте. Это дает количество элементов, которые впоследствии сравниваются. @_ == '!' просто странно.)


Что вы действительно хотите сделать, так это сопоставить введенные значения со списком символов. Ваш хэш определяет это сопоставление, но мы хотим его применить. В Perl есть функция map, она работает как

@out_list = map { ACTION } @in_list;

Внутри блока действий текущее значение доступно как $_.

Мы хотим, чтобы наше действие искало соответствующее значение в хеше или включало сообщение об ошибке, если для входной строки нет сопоставления:

my @letters = map { $morsecode{$_} // "<unknown code $_>" } @message;

Это предполагает, что ! зарегистрировано как пробел в хэше кода Морзе.

Затем мы создаем единую строку из этих букв, joinсоединяя их с пустой строкой:

my $translated_message = join "", @letters;

И не забудьте распечатать результат!


Полный код:

#!/usr/bin/perl
use strict; use warnings; use 5.012;

my %morsecode=(
  '.-'    =>'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',  '.----' =>'1',  '..---' =>'2',
  '...--' =>'3',  '....-' =>'4',  '.....' =>'5',  '-....' =>'6',
  '--...' =>'7',  '---..' =>'8',  '----.' =>'9',  '-----' =>'0',
  '.-.-.-'=>'.',  '--..--'=>',',  '---...'=>':',  '..--..'=>'?',
  '.----.'=>'\'', '-...-' =>'-',  '-..-.' =>'/',  '.-..-.'=>'"',
  '!'     =>' ',
);

say "Please type in your morse message:";
my @codes = <>;
chomp @codes;

my $message = join "", map { $morsecode{$_} // "<unknown code $_>" } @codes;

say "You said:";
say $message;

Это дает желаемый результат.

person amon    schedule 25.01.2013
comment
Это дает желаемый результат... если каждый символ находится в отдельной строке? - person mob; 26.01.2013
comment
@mob Он придерживается формата ввода, указанного OP. Вывод не содержит новых строк. - person amon; 26.01.2013
comment
Хороший! Узнал больше, чем я надеялся. Хорошие объяснения. - person JLott; 26.01.2013

Очень важно узнать, как и почему, но вот что:

sub encode {
  my $output;
  foreach my $symbol (@_) {
    my $letter = $morsecode{$symbol};
    die "Don't know how to decode $symbol" unless defined $letter;
    $output .= $letter
  }
  return $output;
}

или даже всего sub encode { join '', map $morsecode{$_}, @_ }, если вы не слишком беспокоитесь о проверке ошибок. @k и @v ни для чего не нужны.

person hobbs    schedule 25.01.2013

Поиск значений в хэшах — очень интенсивная работа, вам лучше просто использовать обратный хеш. Вы можете легко обратить хэш с помощью обратной функции в Perl. Кроме того, наблюдая за вашим кодом, я увидел, что вы сможете вводить строчные буквы. Но при поиске в хэшах по ключам учитывается регистр. Таким образом, вам нужно заглавные вводимые данные. Кроме того, мне не очень нравится способ «завершить» STDIN. Выходное слово/знак было бы лучше и чище.

Мое мнение о вашем коде

my %morsecode=(
    '.-'    =>'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',  '.----' =>'1',  '..---' =>'2',
    '...--' =>'3',  '....-' =>'4',  '.....' =>'5',  '-....' =>'6',
    '--...' =>'7',  '---..' =>'8',  '----.' =>'9',  '-----' =>'0',
    '.-.-.-'=>'.',  '--..--'=>',',  '---...'=>':',  '..--..'=>'?',
    '.----.'=>'\'', '-...-' =>'-',  '-..-.' =>'/',  '.-..-.'=>'\"'
);
my %reversemorse = reverse %morsecode;
print "Enter a message\n";
chomp (my $message = <STDIN>);
print &encode($message);

sub encode{
    my $origmsg = shift(@_);
    my @letters = split('',$origmsg);
    my $morse = '';
    foreach $l(@letters)
    {
        $morse .= $reversemorse{uc($l)}." ";
    }    
    return $morse;
}
person Tom    schedule 25.01.2013