PHP азбука Морзе

Я пишу основной конвертер кода Морзе в PHP, который может взять строку и преобразовать ее в код Морзе. Он использует ассоциативный массив, цикл foreach и цикл for. Это работает, за исключением того, что по какой-то причине он выводит код Морзе, эквивалентный '0' после каждого преобразованного символа. Я не могу понять, откуда 0. Если я удалю 0 из ассоциативного массива, проблем не будет, но я хочу иметь возможность также преобразовывать числа. Если кто-нибудь сможет дать мне обратную связь, это будет высоко ценится.

Вот код:

<?php
$string = "dog";
$string_lower = strtolower($string);
$assoc_array = 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"=>"--..", 
    "0"=>"-----",
    "1"=>".----", 
    "2"=>"..---", 
    "3"=>"...--", 
    "4"=>"....-", 
    "5"=>".....", 
    "6"=>"-....", 
    "7"=>"--...", 
    "8"=>"---..", 
    "9"=>"----.",
    "."=>".-.-.-",
    ","=>"--..--",
    "?"=>"..--..",
    "/"=>"-..-.",
    " "=>" ");
    for($i=0;$i<strlen($string_lower);$i++){
        foreach($assoc_array as $letter => $code){
            if($letter == $string_lower[$i]){
                echo "$code<br/>";
            }
        }
    }
?>

5 ответов

Решение

Основная проблема в том, что вы делаете "больше", чем необходимо. Там нет необходимости перебирать ваш $assoc_array например, когда вы можете использовать строку для извлечения необходимых данных из нее.

Это также использует меньше ресурсов, так как вместо цикла из a-z а также 0-9 Вы только зацикливаете точное количество букв / цифр / пробелов.

/*Rest of your code above*/
for($i=0;$i<strlen($string_lower);$i++){
    echo (isset($assoc_array[$string_lower[$i]])) ? $assoc_array[$string_lower[$i]] . '<br />' : 'ERROR';       
} 

Так как ваш массив содержит все от a-z а также 0-9 Вы можете легко позвонить по нужным буквам, не беспокоясь о пропущенных данных.

Редактировать: Добавлено isset() проверить, это вряд ли понадобится, так как $assoc_array охватывает все необходимые буквы / цифры, но лучше, чем потом сожалеть. (Благодарим @Farkie за напоминание)

Самое простое исправление - это просто добавить 'break' после echo:

foreach($assoc_array as $letter => $code){
                if($letter == $string_lower[$i]){
                        echo "$code<br/>";
                        break;
                }
        }

Реальная проблема заключается в том, что 0 оценивается как ложное, что означает, что когда оно зацикливается на нем, оно будет истинным (false == false).

Вы можете решить это даже лучше, сделав идентичный (===) матч:

foreach($assoc_array as $letter => $code){
                if($letter === $string_lower[$i]){
                        echo "$code<br/>";
                        break;
                }
        }

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

Код

/**
 * Convert string to morse
 *
 * @param string $string
 * @return string
 */
function str_to_morse(string $string) {
    // Make the string lowercase and create an array of the characters
    $stringParts = str_split(strtolower($string));

    // Define the dictionary
    $morseDictionary = [
        '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' => '--..',
        '0' => '-----',
        '1' => '.----',
        '2' => '..---',
        '3' => '...--',
        '4' => '....-',
        '5' => '.....',
        '6' => '-....',
        '7' => '--...',
        '8' => '---..',
        '9' => '----.',
        '.' => '.-.-.-',
        ',' => '--..--',
        '?' => '..--..',
        '/' => '-..-.',
        ' ' => ' ',
    ];

    $morse = '';
    foreach ($stringParts as $stringPart) {
        if (array_key_exists($stringPart, $morseDictionary)) {
            $morse .= $morseDictionary[$stringPart] . '<br />';
        }
    }

    return $morse;
}

Вы также можете использовать немного php функционального программирования, такого как array_reduce() функция http://php.net/manual/en/function.array-reduce.php

Как избежать всех этих уродливых циклов и упростить ваш код:

$convert = function($carry, $item) {
    $table = array(
        "a" => ".-",
        "b" => "-...",
        "c" => "-.-.",
        "d" => "-..",
        "g" => "--.",
        "o" => "---");
    // Get the correspondent value for the given letter
    $morse = $table[$item];
    // Return the string with appended morse character
    return $carry . $morse;
};

// Split 'dog' into an array, then apply a reduce to convert it to morse
array_reduce(str_split('dog'), $convert);
// ➜  ~ php morse.php                                                     
// -..-----.

Похоже, это самый ранний вопрос кодирования/декодирования азбуки Морзе для языка PHP, поэтому я полагаю, что это лучшее место, чтобы указать, что PHP имеет собственную функцию, которая может переводить подстроки с использованием ассоциативного массива.

будет искать самое длинное квалификационное совпадение и заменять найденную подстроку. не заменит замены в отличие отstr_replace().preg_методы не кажутся оправданными для этой задачи.

Как только ваша входная строка будет переведена в нижний регистр (чтобы соответствовать ключам массива поиска/перевода), и у вас есть какой-то символ-разделитель между каждым символом, вам не нужен цикл — нужен толькоstrtr().

Код для азбуки Морзе: (Демонстрация)

      $string = "d o g";
echo strtr($string, CHAR_TO_MORSE);
// output: -.. --- --.

Инвертировать перевод так же просто, как перевернуть массив поиска/перевода.

Код для декодирования Морзе (Демо)

      $string = "-.. --- --.";
echo strtr($string, array_flip(CHAR_TO_MORSE));
// output: d o g

Константа поиска (на основе массива переводов спрашивающего) может быть объявлена ​​следующим образом:

      const CHAR_TO_MORSE = [
    "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" => "--..",  "0" => "-----",  "1" => ".----",  "2" => "..---",  "3" => "...--", 
    "4" => "....-", "5" => ".....",  "6" => "-....",  "7" => "--...",  "8" => "---..", 
    "9" => "----.", "." => ".-.-.-", "," => "--..--", "?" => "..--..", "/" => "-..-.",
];
Другие вопросы по тегам