Простая программа «секретного сообщения»

Поскольку я новичок в Java, мне хотелось узнать, есть ли лучшие способы ответить на один и тот же вопрос. Являются ли части моего кода избыточными или, возможно, есть более простой способ получить тот же результат?

Проблема J4: секреты большого взрыва . Алгоритм кодирования представляет собой цезарский шифр со сдвигом ( S ), который зависит от параметра ( K ) и его положения в слове ( P , где P = 1 для первой буквы каждого слова): S = 3 P + K . Например, когда K = 3, ZOOM закодирован как FXAB:

  • \ $ S_1 = 3 \ times 1 + 3 = 6 \ $, поэтому ZF
  • \ $ S_2 = 3 \ times 2 + 3 = 9 \ $, поэтому OX
  • \ $ S_3 = 3 \ times 3 + 3 = 12 \ $, поэтому OA
  • \ $ S_4 = 3 \ times 4 + 3 = 15 \ $, поэтому MB

Задача состоит в том, чтобы написать декодер. Первая строка ввода содержит K ( K <10). Вторая строка содержит закодированное сообщение, содержащее до 20 символов в верхнем регистре.

public class Decoder {

public static void main(String[] args) {
    try {

        BufferedReader in = new BufferedReader(new InputStreamReader(
                System.in));
        int k = Integer.parseInt(in.readLine());
        String word = in.readLine();

        char[] cArray = word.toCharArray();

        for (int i = 0; i < word.length(); i++) {

            char out = (char) ((cArray[i]) - (((3 * (i + 1)) + k) % ('Z' - 'A')));

            if (out < 'A') {
                char wrap = (char) (('Z' + 1) - ('A' - out));
                System.out.print(wrap);
            } else {

                System.out.print(out);
            }
        }

    } catch (IOException e) {

        System.out.println("Error");

    }
}
}
12 голосов | спросил quidproquo 29 Jam1000000amThu, 29 Jan 2015 05:56:13 +030015 2015, 05:56:13

3 ответа


10

Ваша программа отлично справляется с тем, что она выполняет эту работу, но есть некоторые способы значительно улучшить ее реализацию.

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

Затем, используя некоторые из более современных функций Java (те, которые были там с Java7), вы должны использовать оператор try-with-resources для управления исключениями ввода.

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

Иногда легче показать, чем рассказывать. Начнем с основной процедуры декодирования. Эти два метода должны иметь смысл:

public static final String decode(final int key, final String encoded) {
    final int len = encoded.length();
    // prepare a space to store the decoded value
    final char[] decoded = new char[len];
    for (int i = 0; i < len; i++) {
        // use i+1 here since the algorithm has the first char at position 1, not 0.
        decoded[i] = decodeChar(encoded.charAt(i), i + 1, key);
    }
    // convert the decoded chars back to a String.
    return new String(decoded);
}

private static char decodeChar(final char encoded, final int position, final int key) {
    // modulo 26 eliminates multiple wrap-arounds.
    int rotate = (3 * position + key) % 26;
    // apply the rotation shift to the input
    int decval = (encoded - 'A') + 26 - rotate;
    // use another % 26 to keep the letters in range.
    return (char)('A' + (decval % 26));
}

Обратите внимание, что использование функции извлечения делает код более простым?

Теперь, как получить вход в эту функцию? Это было бы просто:

public static void main(String[] args) {
    CypherText input = getEncoded();
    String decoded = decode(input.getKey(), input.getText());
    System.out.println("Decoded: " + decoded);
}

Обратите внимание, что класс CypherText является новым .... но вы можете четко видеть, как decode(...). Biw - это CypherText?

private static final class CypherText {
    private final int key;
    private final String text;

    public CypherText(int key, String text) {
        super();
        this.key = key;
        this.text = text;
    }

    public int getKey() {
        return key;
    }

    public String getText() {
        return text;
    }

}

public static CypherText getEncoded() {
    try (BufferedReader reader = new BufferedReader(new InputStreamReader(System.in))){
        int k = Integer.parseInt(reader.readLine());
        String word = reader.readLine();
        return new CypherText(k, word);
    } catch (IOException e) {
        e.printStackTrace();
        return new CypherText(0, "");
    }
}

Я помещаю в Ideone здесь

ответил rolfl 29 Jam1000000amThu, 29 Jan 2015 08:04:20 +030015 2015, 08:04:20
5

Я сделаю следующие предложения:

  • Используйте Scanner для немного более удобного интерфейса, чем new BufferedReader(new InputStreamReader(…))
  • Для удобства чтения разделите работу на
    • Ввод /вывод
    • Создание экземпляра для параметра K
    • Вычисление, сколько нужно сдвинуть отдельную букву
    • Применение сдвига для отдельной буквы
  • Используйте modulo арифметику для устранения особых случаев.
  • Распечатайте результат сразу как new String(…).
  • Если вам нужно распечатать сообщение об ошибке, напечатайте его на System.err, чтобы избежать заражения System.out, где он будет интерпретироваться как законный вывод.

Рекомендуемая реализация

import java.util.Scanner;

public class BigBangCipher {
    private int k;

    public BigBangCipher(int k) {
        this.k = k;
    }

    /**
     * Shift for a character, given a 0-based index.
     */
    private int shift(int pos) {
        return 3 * (pos + 1) + this.k;
    }

    /**
     * Applies a Caesar cipher shift for an uppercase character.
     */
    private static char caesar(char c, int shift) {
        return (char)('A' + (c + shift - 'A' + 26) % 26);
    }

    public String decode(CharSequence cipherText) {
        char[] s = new char[cipherText.length()];
        for (int i = 0; i < s.length; i++) {
            s[i] = caesar(cipherText.charAt(i), -this.shift(i));
        }
        return new String(s);
    }

    public static void main(String[] args) {
        try (Scanner in = new Scanner(System.in)) {
            int k = Integer.parseInt(in.nextLine());
            BigBangCipher cipher = new BigBangCipher(k);
            System.out.println(cipher.decode(in.nextLine()));
        }
    }
}
ответил 200_success 29 Jam1000000amThu, 29 Jan 2015 11:30:33 +030015 2015, 11:30:33
5

Ваше решение кажется вообще здоровым. Я бы сделал несколько изменений:

Вы окружаете весь свой код в блоке try-catch. Вместо этого, окружайте область, в которой IOException имеет шанс быть выброшенным (Также используйте System.err для печати на наличие ошибок):

try {
    BufferedReader in = new BufferedReader(new InputStreamReader(
            System.in));
} catch (IOException) {
    System.err.println("Error");
}

И поскольку in находится внутри try-catch и требуется снаружи, do:

BufferedReader in = null;
try {
    in = new BufferedReader(new InputStreamReader(
            System.in));
} catch (IOException) {
    System.err.println("Error");
    return;
}
ответил TheCoffeeCup 29 Jam1000000amThu, 29 Jan 2015 06:21:13 +030015 2015, 06:21:13

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132