From 8289598dd4520fdf00da2ef99eed11c8bd1f1d45 Mon Sep 17 00:00:00 2001 From: Daniil Timoshenko Date: Sun, 31 Aug 2025 18:13:47 +0200 Subject: [PATCH 1/2] =?UTF-8?q?1=20=D0=9A=D0=9E=D0=9C=D0=9C=D0=98=D0=A2.?= =?UTF-8?q?=20=D0=9A=D0=BE=D0=BC=D0=BF=D0=B8=D0=BB=D0=B8=D1=80=D1=83=D0=B5?= =?UTF-8?q?=D0=BC=D1=8B=D0=B9=20=D0=BA=D1=80=D0=B8=D0=BF=D1=82=D0=BE=D0=B0?= =?UTF-8?q?=D0=BD=D0=B0=D0=BB=D0=B8=D0=B7=D0=B0=D1=82=D0=BE=D1=80.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/javarush/timoshenko/MainApp.java | 219 ++++++++++++++++++ .../javarush/timoshenko/core/BruteForce.java | 122 ++++++++++ .../timoshenko/core/CaesarCipher.java | 66 ++++++ .../javarush/timoshenko/core/FileManager.java | 26 +++ .../timoshenko/core/StatisticalAnalyzer.java | 66 ++++++ .../javarush/timoshenko/core/Validator.java | 33 +++ .../timoshenko/exception/CipherException.java | 19 ++ 7 files changed, 551 insertions(+) create mode 100644 src/main/java/com/javarush/timoshenko/MainApp.java create mode 100644 src/main/java/com/javarush/timoshenko/core/BruteForce.java create mode 100644 src/main/java/com/javarush/timoshenko/core/CaesarCipher.java create mode 100644 src/main/java/com/javarush/timoshenko/core/FileManager.java create mode 100644 src/main/java/com/javarush/timoshenko/core/StatisticalAnalyzer.java create mode 100644 src/main/java/com/javarush/timoshenko/core/Validator.java create mode 100644 src/main/java/com/javarush/timoshenko/exception/CipherException.java diff --git a/src/main/java/com/javarush/timoshenko/MainApp.java b/src/main/java/com/javarush/timoshenko/MainApp.java new file mode 100644 index 0000000..75bec65 --- /dev/null +++ b/src/main/java/com/javarush/timoshenko/MainApp.java @@ -0,0 +1,219 @@ +package com.javarush.timoshenko; + +import com.javarush.timoshenko.core.*; +import com.javarush.timoshenko.exception.CipherException; +import java.util.Scanner; + +public class MainApp { + private FileManager fileManager; + private Validator validator; + private CaesarCipher cipher; + private BruteForce bruteForce; + private StatisticalAnalyzer statisticalAnalyzer; + private Scanner scanner; + private char[] currentAlphabet; + + public MainApp() { + scanner = new Scanner(System.in); + selectAlphabet(); + initializeComponents(); + } + + private void selectAlphabet() { + System.out.println("=== Выбор алфавита ==="); + System.out.println("1. Русский алфавит"); + System.out.println("2. Английский алфавит"); + + int choice = getIntInput("Выберите алфавит: "); + + switch (choice) { + case 1 -> currentAlphabet = CaesarCipher.RUSSIAN_ALPHABET; + case 2 -> currentAlphabet = CaesarCipher.ENGLISH_ALPHABET; + default -> { + System.out.println("Неверный выбор. Используется русский алфавит."); + currentAlphabet = CaesarCipher.RUSSIAN_ALPHABET; + } + } + + System.out.println("Выбран алфавит: " + + (currentAlphabet == CaesarCipher.RUSSIAN_ALPHABET ? "Русский" : "Английский")); + } + + private void initializeComponents() { + fileManager = new FileManager(); + validator = new Validator(currentAlphabet); + cipher = new CaesarCipher(currentAlphabet); + bruteForce = new BruteForce(cipher); + statisticalAnalyzer = new StatisticalAnalyzer(cipher); + } + + public void run() { + while (true) { + printMenu(); + int choice = getIntInput("Выберите опцию: "); + + switch (choice) { + case 1 -> encrypt(); + case 2 -> decryptWithKey(); + case 3 -> bruteForceDecrypt(); + case 4 -> statisticalAnalysis(); + case 5 -> changeAlphabet(); + case 0 -> { + System.out.println("Выход из программы."); + return; + } + default -> System.out.println("Неверный выбор. Попробуйте снова."); + } + } + } + + private void printMenu() { + System.out.println("\n=== Шифр Цезаря ==="); + System.out.println("Алфавит: " + + (currentAlphabet == CaesarCipher.RUSSIAN_ALPHABET ? "Русский" : "Английский")); + System.out.println("1. Зашифровать текст"); + System.out.println("2. Расшифровать текст с ключом"); + System.out.println("3. Взлом brute force"); + System.out.println("4. Статистический анализ"); + System.out.println("5. Сменить алфавит"); + System.out.println("0. Выход"); + } + + private void encrypt() { + try { + String inputFile = getFileInput("Введите путь к исходному файлу: ", false); + String outputFile = getFileInput("Введите путь для сохранения результата: ", true); + int key = getIntInput("Введите ключ (число от 0 до " + (currentAlphabet.length - 1) + "): "); + + if (!validator.isValidKey(key)) { + System.out.println("Неверный ключ!"); + return; + } + + String text = fileManager.readFile(inputFile); + String encrypted = cipher.encrypt(text, key); + fileManager.writeFile(encrypted, outputFile); + + System.out.println("Текст успешно зашифрован и сохранен в: " + outputFile); + + } catch (CipherException e) { + System.out.println("Ошибка при шифровании: " + e.getMessage()); + } + } + + private void decryptWithKey() { + try { + String inputFile = getFileInput("Введите путь к зашифрованному файлу: ", false); + String outputFile = getFileInput("Введите путь для сохранения результата: ", true); + int key = getIntInput("Введите ключ: "); + + if (!validator.isValidKey(key)) { + System.out.println("Неверный ключ!"); + return; + } + + String text = fileManager.readFile(inputFile); + String decrypted = cipher.decrypt(text, key); + fileManager.writeFile(decrypted, outputFile); + + System.out.println("Текст успешно расшифрован и сохранен в: " + outputFile); + + } catch (CipherException e) { + System.out.println("Ошибка при расшифровке: " + e.getMessage()); + } + } + + private void bruteForceDecrypt() { + try { + String inputFile = getFileInput("Введите путь к зашифрованному файлу: ", false); + String sampleFile = getFileInput("Введите путь к файлу-образцу (или Enter чтобы пропустить): ", true); + String outputFile = getFileInput("Введите путь для сохранения результата: ", true); + + String encryptedText = fileManager.readFile(inputFile); + String sampleText = ""; + + if (!sampleFile.isEmpty() && validator.isFileExists(sampleFile)) { + sampleText = fileManager.readFile(sampleFile); + } + + String decrypted = bruteForce.decryptByBruteForce(encryptedText, sampleText); + fileManager.writeFile(decrypted, outputFile); + + System.out.println("Brute force завершен. Результат сохранен в: " + outputFile); + + } catch (CipherException e) { + System.out.println("Ошибка при brute force: " + e.getMessage()); + } + } + + private void statisticalAnalysis() { + try { + String inputFile = getFileInput("Введите путь к зашифрованному файлу: ", false); + String sampleFile = getFileInput("Введите путь к файлу-образцу: ", false); + String outputFile = getFileInput("Введите путь для сохранения результата: ", true); + + String encryptedText = fileManager.readFile(inputFile); + String sampleText = fileManager.readFile(sampleFile); + + int shift = statisticalAnalyzer.findMostLikelyShift(encryptedText, sampleText); + String decrypted = cipher.decrypt(encryptedText, shift); + + fileManager.writeFile(decrypted, outputFile); + + System.out.println("Статистический анализ завершен. Найденный ключ: " + shift); + System.out.println("Результат сохранен в: " + outputFile); + + } catch (CipherException e) { + System.out.println("Ошибка при статистическом анализе: " + e.getMessage()); + } + } + + private void changeAlphabet() { + selectAlphabet(); + initializeComponents(); + System.out.println("Алфавит изменен."); + } + + private String getFileInput(String prompt, boolean canBeEmpty) { + while (true) { + System.out.print(prompt); + String input = scanner.nextLine().trim(); + + if (input.isEmpty() && canBeEmpty) { + return input; + } + + if (input.isEmpty() && !canBeEmpty) { + System.out.println("Путь не может быть пустым."); + continue; + } + + if (!canBeEmpty && !validator.isFileExists(input)) { + System.out.println("Файл не существует: " + input); + continue; + } + + if (canBeEmpty && !input.isEmpty() && !validator.isValidOutputPath(input)) { + System.out.println("Невозможно записать в указанный путь: " + input); + continue; + } + + return input; + } + } + + private int getIntInput(String prompt) { + while (true) { + System.out.print(prompt); + try { + return Integer.parseInt(scanner.nextLine().trim()); + } catch (NumberFormatException e) { + System.out.println("Пожалуйста, введите целое число."); + } + } + } + + public static void main(String[] args) { + new MainApp().run(); + } +} diff --git a/src/main/java/com/javarush/timoshenko/core/BruteForce.java b/src/main/java/com/javarush/timoshenko/core/BruteForce.java new file mode 100644 index 0000000..f9b39c8 --- /dev/null +++ b/src/main/java/com/javarush/timoshenko/core/BruteForce.java @@ -0,0 +1,122 @@ +package com.javarush.timoshenko.core; + +public class BruteForce { + private final CaesarCipher cipher; + + public BruteForce(CaesarCipher cipher) { + this.cipher = cipher; + } + + public String decryptByBruteForce(String encryptedText, String sampleText) { + int bestKey = 0; + double bestMatch = 0; + char[] alphabet = cipher.getAlphabet(); + + // Перебираем все возможные ключи + for (int key = 0; key < alphabet.length; key++) { + String decrypted = cipher.decrypt(encryptedText, key); + double matchScore = calculateMatchScore(decrypted, sampleText); + + if (matchScore > bestMatch) { + bestMatch = matchScore; + bestKey = key; + } + } + + return cipher.decrypt(encryptedText, bestKey); + } + + private double calculateMatchScore(String text, String sampleText) { + if (sampleText == null || sampleText.isEmpty()) { + // Если нет образца, используем частоту букв выбранного алфавита + return calculateLetterFrequency(text); + } + + // Считаем частоту символов в образце и сравниваем + return calculateFrequencySimilarity(text, sampleText); + } + + private double calculateLetterFrequency(String text) { + char[] alphabet = cipher.getAlphabet(); + boolean isRussian = alphabet == CaesarCipher.RUSSIAN_ALPHABET; + + // Частоты букв ТОЛЬКО для буквенных частей алфавитов + double[] expectedFrequencies; + int letterCount; // Количество букв в алфавите + + if (isRussian) { + // Русские частоты (для 32 букв) + expectedFrequencies = new double[]{ + 0.0801, 0.0159, 0.0454, 0.0170, 0.0298, 0.0845, 0.0094, 0.0165, 0.0735, + 0.0121, 0.0349, 0.0440, 0.0321, 0.0670, 0.1097, 0.0281, 0.0473, 0.0547, + 0.0626, 0.0262, 0.0026, 0.0097, 0.0048, 0.0144, 0.0073, 0.0036, 0.0004, + 0.0190, 0.0174, 0.0032, 0.0064, 0.0201 + }; + letterCount = 32; + } else { + // Английские частоты (для 26 букв) + expectedFrequencies = new double[]{ + 0.0812, 0.0149, 0.0271, 0.0432, 0.1202, 0.0230, 0.0203, 0.0592, 0.0731, + 0.0010, 0.0069, 0.0398, 0.0261, 0.0695, 0.0768, 0.0182, 0.0011, 0.0602, + 0.0628, 0.0910, 0.0288, 0.0111, 0.0209, 0.0017, 0.0211, 0.0007 + }; + letterCount = 26; + } + + int[] actualCounts = new int[letterCount]; + int totalLetters = 0; + + // Считаем ТОЛЬКО буквы в тексте (первые letterCount символов алфавита) + for (char c : text.toLowerCase().toCharArray()) { + for (int i = 0; i < letterCount; i++) { // Цикл только по буквам + if (c == alphabet[i]) { + actualCounts[i]++; + totalLetters++; + break; + } + } + } + + if (totalLetters == 0) return 0; + + double correlation = 0; + for (int i = 0; i < letterCount; i++) { + double actualFrequency = (double) actualCounts[i] / totalLetters; + correlation += Math.min(actualFrequency, expectedFrequencies[i]); + } + + return correlation; + } + + private double calculateFrequencySimilarity(String text, String sample) { + char[] alphabet = cipher.getAlphabet(); + + int[] textFreq = calculateCharacterFrequency(text, alphabet); + int[] sampleFreq = calculateCharacterFrequency(sample, alphabet); + + double similarity = 0; + int total = 0; + + for (int i = 0; i < textFreq.length; i++) { + if (sampleFreq[i] > 0) { + similarity += Math.min(textFreq[i], sampleFreq[i]); + total += sampleFreq[i]; + } + } + + return total > 0 ? similarity / total : 0; + } + + private int[] calculateCharacterFrequency(String text, char[] alphabet) { + int[] frequency = new int[alphabet.length]; + for (char c : text.toLowerCase().toCharArray()) { + for (int i = 0; i < alphabet.length; i++) { + if (c == alphabet[i]) { + frequency[i]++; + break; + } + } + } + return frequency; + } +} diff --git a/src/main/java/com/javarush/timoshenko/core/CaesarCipher.java b/src/main/java/com/javarush/timoshenko/core/CaesarCipher.java new file mode 100644 index 0000000..c54c9ed --- /dev/null +++ b/src/main/java/com/javarush/timoshenko/core/CaesarCipher.java @@ -0,0 +1,66 @@ +package com.javarush.timoshenko.core; + +import java.util.HashMap; +import java.util.Map; + +public class CaesarCipher { + public static final char[] RUSSIAN_ALPHABET = { + 'а', 'б', 'в', 'г', 'д', 'е', 'ж', 'з', 'и', 'й', 'к', 'л', 'м', 'н', 'о', + 'п', 'р', 'с', 'т', 'у', 'ф', 'х', 'ц', 'ч', 'ш', 'щ', 'ъ', 'ы', 'ь', 'э', + 'ю', 'я', '.', ',', '«', '»', '"', '\'', ':', '!', '?', ' ' + }; + + public static final char[] ENGLISH_ALPHABET = { + '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', '.', ',', '"', '\'', + ':', '!', '?', ' ' + }; + + private final Map charToIndex; + private final char[] alphabet; + + public CaesarCipher(char[] alphabet) { + this.alphabet = alphabet; + this.charToIndex = new HashMap<>(); + for (int i = 0; i < alphabet.length; i++) { + charToIndex.put(alphabet[i], i); + } + } + + public String encrypt(String text, int shift) { + return processText(text, shift); + } + + public String decrypt(String encryptedText, int shift) { + return processText(encryptedText, alphabet.length - (shift % alphabet.length)); + } + + private String processText(String text, int shift) { + StringBuilder result = new StringBuilder(); + + for (char character : text.toCharArray()) { + char lowerChar = Character.toLowerCase(character); + Integer index = charToIndex.get(lowerChar); + + if (index != null) { + int newIndex = (index + shift) % alphabet.length; + char encryptedChar = alphabet[newIndex]; + + // Сохраняем регистр оригинального символа + if (Character.isUpperCase(character)) { + encryptedChar = Character.toUpperCase(encryptedChar); + } + + result.append(encryptedChar); + } else { + result.append(character); + } + } + + return result.toString(); + } + + public char[] getAlphabet() { + return alphabet; + } +} diff --git a/src/main/java/com/javarush/timoshenko/core/FileManager.java b/src/main/java/com/javarush/timoshenko/core/FileManager.java new file mode 100644 index 0000000..1cd8d48 --- /dev/null +++ b/src/main/java/com/javarush/timoshenko/core/FileManager.java @@ -0,0 +1,26 @@ +package com.javarush.timoshenko.core; + +import com.javarush.timoshenko.exception.CipherException; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; + +public class FileManager { + + public String readFile(String filePath) throws CipherException { + try { + return new String(Files.readAllBytes(Paths.get(filePath))); + } catch (IOException e) { + throw new CipherException("Ошибка чтения файла: " + filePath, e); + } + } + + public void writeFile(String content, String filePath) throws CipherException { + try { + Files.write(Paths.get(filePath), content.getBytes()); + } catch (IOException e) { + throw new CipherException("Ошибка записи в файл: " + filePath, e); + } + } +} diff --git a/src/main/java/com/javarush/timoshenko/core/StatisticalAnalyzer.java b/src/main/java/com/javarush/timoshenko/core/StatisticalAnalyzer.java new file mode 100644 index 0000000..656fcec --- /dev/null +++ b/src/main/java/com/javarush/timoshenko/core/StatisticalAnalyzer.java @@ -0,0 +1,66 @@ +package com.javarush.timoshenko.core; + +public class StatisticalAnalyzer { + private final CaesarCipher cipher; + + public StatisticalAnalyzer(CaesarCipher cipher) { + this.cipher = cipher; + } + + public int findMostLikelyShift(String encryptedText, String representativeText) { + int bestShift = 0; + double bestScore = 0; + char[] alphabet = cipher.getAlphabet(); + + // Частоты символов в representative тексте + int[] refFrequencies = calculateCharacterFrequency(representativeText, alphabet); + + for (int shift = 0; shift < alphabet.length; shift++) { + String decrypted = cipher.decrypt(encryptedText, shift); + int[] decryptedFrequencies = calculateCharacterFrequency(decrypted, alphabet); + + double score = calculateFrequencyScore(decryptedFrequencies, refFrequencies); + + if (score > bestScore) { + bestScore = score; + bestShift = shift; + } + } + + return bestShift; + } + + private int[] calculateCharacterFrequency(String text, char[] alphabet) { + int[] frequency = new int[alphabet.length]; + int total = 0; + + for (char c : text.toLowerCase().toCharArray()) { + for (int i = 0; i < alphabet.length; i++) { + if (c == alphabet[i]) { + frequency[i]++; + total++; + break; + } + } + } + + // Нормализуем частоты + if (total > 0) { + for (int i = 0; i < frequency.length; i++) { + frequency[i] = (frequency[i] * 1000) / total; + } + } + + return frequency; + } + + private double calculateFrequencyScore(int[] freq1, int[] freq2) { + double score = 0; + for (int i = 0; i < freq1.length; i++) { + if (freq2[i] > 0) { + score += Math.min(freq1[i], freq2[i]); + } + } + return score; + } +} diff --git a/src/main/java/com/javarush/timoshenko/core/Validator.java b/src/main/java/com/javarush/timoshenko/core/Validator.java new file mode 100644 index 0000000..632ca26 --- /dev/null +++ b/src/main/java/com/javarush/timoshenko/core/Validator.java @@ -0,0 +1,33 @@ +package com.javarush.timoshenko.core; + +import java.io.File; + +public class Validator { + private final char[] alphabet; + + public Validator(char[] alphabet) { + this.alphabet = alphabet; + } + + public boolean isValidKey(int key) { + return key >= 0 && key < alphabet.length; + } + + public boolean isFileExists(String filePath) { + return new File(filePath).exists(); + } + + public boolean isValidOutputPath(String filePath) { + try { + java.nio.file.Path path = java.nio.file.Paths.get(filePath); + java.nio.file.Path parent = path.getParent(); + return parent == null || java.nio.file.Files.exists(parent) || java.nio.file.Files.isWritable(parent); + } catch (Exception e) { + return false; + } + } + + public char[] getAlphabet() { + return alphabet; + } +} diff --git a/src/main/java/com/javarush/timoshenko/exception/CipherException.java b/src/main/java/com/javarush/timoshenko/exception/CipherException.java new file mode 100644 index 0000000..4453499 --- /dev/null +++ b/src/main/java/com/javarush/timoshenko/exception/CipherException.java @@ -0,0 +1,19 @@ +package com.javarush.timoshenko.exception; + +/** + * Базовое исключение для приложения шифра Цезаря + */ +public class CipherException extends Exception { + + public CipherException(String message) { + super(message); + } + + public CipherException(String message, Throwable cause) { + super(message, cause); + } + + public CipherException(Throwable cause) { + super(cause); + } +} From 2af92bf32afff452e4f2ed8d2759b21bd38f31ce Mon Sep 17 00:00:00 2001 From: Daniil Timoshenko Date: Mon, 1 Sep 2025 21:59:57 +0200 Subject: [PATCH 2/2] =?UTF-8?q?2=20=D0=9A=D0=9E=D0=9C=D0=9C=D0=98=D0=A2.?= =?UTF-8?q?=20=D0=9A=D0=BE=D0=BC=D0=BF=D0=B8=D0=BB=D0=B8=D1=80=D1=83=D0=B5?= =?UTF-8?q?=D0=BC=D1=8B=D0=B9=20=D0=BA=D1=80=D0=B8=D0=BF=D1=82=D0=BE=D0=B0?= =?UTF-8?q?=D0=BD=D0=B0=D0=BB=D0=B8=D0=B7=D0=B0=D1=82=D0=BE=D1=80.=20?= =?UTF-8?q?=D0=A3=D0=B1=D1=80=D0=B0=D0=BB=20=D0=BF=D0=BE=D1=8F=D1=81=D0=BD?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D1=8F.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/javarush/timoshenko/core/BruteForce.java | 15 ++++++--------- .../javarush/timoshenko/core/CaesarCipher.java | 2 +- .../timoshenko/core/StatisticalAnalyzer.java | 4 ++-- .../timoshenko/exception/CipherException.java | 4 +--- 4 files changed, 10 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/javarush/timoshenko/core/BruteForce.java b/src/main/java/com/javarush/timoshenko/core/BruteForce.java index f9b39c8..4b93a14 100644 --- a/src/main/java/com/javarush/timoshenko/core/BruteForce.java +++ b/src/main/java/com/javarush/timoshenko/core/BruteForce.java @@ -12,7 +12,7 @@ public String decryptByBruteForce(String encryptedText, String sampleText) { double bestMatch = 0; char[] alphabet = cipher.getAlphabet(); - // Перебираем все возможные ключи + for (int key = 0; key < alphabet.length; key++) { String decrypted = cipher.decrypt(encryptedText, key); double matchScore = calculateMatchScore(decrypted, sampleText); @@ -28,11 +28,11 @@ public String decryptByBruteForce(String encryptedText, String sampleText) { private double calculateMatchScore(String text, String sampleText) { if (sampleText == null || sampleText.isEmpty()) { - // Если нет образца, используем частоту букв выбранного алфавита + return calculateLetterFrequency(text); } - // Считаем частоту символов в образце и сравниваем + return calculateFrequencySimilarity(text, sampleText); } @@ -40,12 +40,11 @@ private double calculateLetterFrequency(String text) { char[] alphabet = cipher.getAlphabet(); boolean isRussian = alphabet == CaesarCipher.RUSSIAN_ALPHABET; - // Частоты букв ТОЛЬКО для буквенных частей алфавитов + double[] expectedFrequencies; - int letterCount; // Количество букв в алфавите + int letterCount; if (isRussian) { - // Русские частоты (для 32 букв) expectedFrequencies = new double[]{ 0.0801, 0.0159, 0.0454, 0.0170, 0.0298, 0.0845, 0.0094, 0.0165, 0.0735, 0.0121, 0.0349, 0.0440, 0.0321, 0.0670, 0.1097, 0.0281, 0.0473, 0.0547, @@ -54,7 +53,6 @@ private double calculateLetterFrequency(String text) { }; letterCount = 32; } else { - // Английские частоты (для 26 букв) expectedFrequencies = new double[]{ 0.0812, 0.0149, 0.0271, 0.0432, 0.1202, 0.0230, 0.0203, 0.0592, 0.0731, 0.0010, 0.0069, 0.0398, 0.0261, 0.0695, 0.0768, 0.0182, 0.0011, 0.0602, @@ -66,9 +64,8 @@ private double calculateLetterFrequency(String text) { int[] actualCounts = new int[letterCount]; int totalLetters = 0; - // Считаем ТОЛЬКО буквы в тексте (первые letterCount символов алфавита) for (char c : text.toLowerCase().toCharArray()) { - for (int i = 0; i < letterCount; i++) { // Цикл только по буквам + for (int i = 0; i < letterCount; i++) { if (c == alphabet[i]) { actualCounts[i]++; totalLetters++; diff --git a/src/main/java/com/javarush/timoshenko/core/CaesarCipher.java b/src/main/java/com/javarush/timoshenko/core/CaesarCipher.java index c54c9ed..1d60e68 100644 --- a/src/main/java/com/javarush/timoshenko/core/CaesarCipher.java +++ b/src/main/java/com/javarush/timoshenko/core/CaesarCipher.java @@ -46,7 +46,7 @@ private String processText(String text, int shift) { int newIndex = (index + shift) % alphabet.length; char encryptedChar = alphabet[newIndex]; - // Сохраняем регистр оригинального символа + if (Character.isUpperCase(character)) { encryptedChar = Character.toUpperCase(encryptedChar); } diff --git a/src/main/java/com/javarush/timoshenko/core/StatisticalAnalyzer.java b/src/main/java/com/javarush/timoshenko/core/StatisticalAnalyzer.java index 656fcec..375e254 100644 --- a/src/main/java/com/javarush/timoshenko/core/StatisticalAnalyzer.java +++ b/src/main/java/com/javarush/timoshenko/core/StatisticalAnalyzer.java @@ -12,7 +12,7 @@ public int findMostLikelyShift(String encryptedText, String representativeText) double bestScore = 0; char[] alphabet = cipher.getAlphabet(); - // Частоты символов в representative тексте + int[] refFrequencies = calculateCharacterFrequency(representativeText, alphabet); for (int shift = 0; shift < alphabet.length; shift++) { @@ -44,7 +44,7 @@ private int[] calculateCharacterFrequency(String text, char[] alphabet) { } } - // Нормализуем частоты + if (total > 0) { for (int i = 0; i < frequency.length; i++) { frequency[i] = (frequency[i] * 1000) / total; diff --git a/src/main/java/com/javarush/timoshenko/exception/CipherException.java b/src/main/java/com/javarush/timoshenko/exception/CipherException.java index 4453499..f4e2816 100644 --- a/src/main/java/com/javarush/timoshenko/exception/CipherException.java +++ b/src/main/java/com/javarush/timoshenko/exception/CipherException.java @@ -1,8 +1,6 @@ package com.javarush.timoshenko.exception; -/** - * Базовое исключение для приложения шифра Цезаря - */ + public class CipherException extends Exception { public CipherException(String message) {