-
Notifications
You must be signed in to change notification settings - Fork 47
add - package morozov #23
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| package com.javarush.morozov; | ||
|
|
||
| import com.javarush.morozov.ui.MainWindow; | ||
|
|
||
| public class App { | ||
| public static void main(String[] args) { | ||
| javax.swing.SwingUtilities.invokeLater(() -> { | ||
| MainWindow mainWindow = new MainWindow(); | ||
| mainWindow.setVisible(true); | ||
| }); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,159 @@ | ||
| package com.javarush.morozov.core; | ||
|
|
||
| import com.javarush.morozov.ui.handlers.MessageHandler; | ||
|
|
||
| import java.util.*; | ||
|
|
||
| public class CaesarCipher { | ||
| public enum Language { | ||
| RUSSIAN("RUS", "Русские"), | ||
| ENGLISH("ENG", "Английские"); | ||
|
|
||
| private final String code; | ||
| private final String displayName; | ||
|
|
||
| Language(String code, String displayName) { | ||
| this.code = code; | ||
| this.displayName = displayName; | ||
| } | ||
|
|
||
| public String getCode() { | ||
| return code; | ||
| } | ||
|
|
||
| public String getDisplayName() { | ||
| return displayName; | ||
| } | ||
|
|
||
| @Override | ||
| public String toString() { | ||
| return displayName; | ||
| } | ||
| } | ||
|
|
||
| private static final char[] RUSSIAN_ALPHABET = { | ||
| 'а', 'б', 'в', 'г', 'д', 'е', 'ж', 'з', 'и', 'й', 'к', 'л', 'м', 'н', 'о', 'п', | ||
| 'р', 'с', 'т', 'у', 'ф', 'х', 'ц', 'ч', 'ш', 'щ', 'ъ', 'ы', 'ь', 'э', 'ю', 'я', | ||
| '.', ',', '«', '»', '"', '\'', ':', '!', '?', ' ' | ||
| }; | ||
|
|
||
| private 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 char[] currentAlphabet; | ||
| private Language currentLanguage; | ||
| private Set<Character> allowedChars; | ||
|
|
||
| public CaesarCipher(Language language) { | ||
| setLanguage(language); | ||
| } | ||
|
|
||
| public void setLanguage(Language language) { | ||
| this.currentLanguage = language; | ||
| this.currentAlphabet = language == Language.RUSSIAN ? RUSSIAN_ALPHABET : ENGLISH_ALPHABET; | ||
| this.allowedChars = new HashSet<>(); | ||
|
|
||
| for (char c : currentAlphabet) { | ||
| allowedChars.add(c); | ||
| } | ||
| } | ||
|
|
||
| public String encrypt(String text, int key) throws IllegalArgumentException { | ||
| validateText(text); | ||
| return processText(text, key); | ||
| } | ||
|
|
||
| public String decrypt(String text, int key) throws IllegalArgumentException { | ||
| validateText(text); | ||
| return processText(text, -key); | ||
| } | ||
|
|
||
| private String processText(String text, int key) { | ||
| StringBuilder result = new StringBuilder(); | ||
| text = text.toLowerCase(); | ||
|
|
||
| for (char c : text.toCharArray()) { | ||
| int index = Arrays.binarySearch(currentAlphabet, c); | ||
|
|
||
| if (index >= 0) { | ||
| int newIndex = (index + key) % currentAlphabet.length; | ||
| if (newIndex < 0) newIndex += currentAlphabet.length; | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Лучше было бы индекс сначала перевести в положительную область а уже потом вычислять остаток отделения, чтобы вся отладка была в положительных значениях, но это дело вкуса конечно. |
||
|
|
||
| result.append(currentAlphabet[newIndex]); | ||
| } else { | ||
| result.append(c); | ||
| } | ||
| } | ||
|
|
||
| return result.toString(); | ||
| } | ||
|
|
||
| private void validateText(String text) throws IllegalArgumentException { | ||
| for (int i = 0; i < text.length(); i++) { | ||
| char c = Character.toLowerCase(text.charAt(i)); | ||
|
|
||
| if (!allowedChars.contains(c)) { | ||
| String errorMessage = "Текст содержит недопустимые символы. Разрешены только " | ||
| + currentLanguage.getDisplayName() + " символы и знаки пунктуации."; | ||
|
|
||
| MessageHandler.showErrorDialog(errorMessage); | ||
|
|
||
| throw new IllegalArgumentException( | ||
| String.format("Недопустимый символ '%c' в позиции %d", text.charAt(i), i) | ||
| ); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Расшифровка методом BruteForce | ||
| * @param encryptedText расшифровываемый текст. | ||
| * @return Список результатов оценки метода BruteForce. | ||
| */ | ||
| public List<BruteForceResult> bruteForce(String encryptedText) { | ||
| List<BruteForceResult> results = new ArrayList<>(); | ||
|
|
||
| for (int key = 1; key < currentAlphabet.length; key++) { | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. если ключ 0 (не зашифровано) то текст испортится. |
||
| String decrypted = processText(encryptedText, -key); | ||
| int score = calculateTextScore(decrypted); | ||
| results.add(new BruteForceResult(decrypted, key, score)); | ||
| } | ||
|
|
||
| results.sort((a, b) -> Integer.compare(b.score, a.score)); | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. тогда уже и все можно было бы стримом сделать |
||
|
|
||
| return results; | ||
| } | ||
|
|
||
| public record BruteForceResult(String text, int key, int score) { | ||
| } | ||
|
|
||
| private int calculateTextScore(String text) { | ||
| int score = 0; | ||
|
|
||
| long spaceCount = text.chars().filter(c -> c == ' ').count(); | ||
| score += (int) (spaceCount * 10); | ||
|
|
||
| String vowels = currentLanguage == Language.RUSSIAN ? "аеёиоуыэюя" : "aeiouy"; | ||
| long vowelCount = text.toLowerCase().chars() | ||
| .filter(c -> vowels.indexOf(c) >= 0) | ||
| .count(); | ||
| score += (int) (vowelCount * 3); | ||
|
|
||
| String commonChars = currentLanguage == Language.RUSSIAN ? "оае" : "eta"; | ||
| long commonCount = text.toLowerCase().chars() | ||
| .filter(c -> commonChars.indexOf(c) >= 0) | ||
| .count(); | ||
| score += (int) (commonCount * 2); | ||
|
|
||
| String punctuation = ".,!?;:\"'"; | ||
|
|
||
| if (text.matches(".*[a-zA-Zа-яА-Я][" + punctuation + "][a-zA-Zа-яА-Я].*")) { | ||
| score -= 20; | ||
| } | ||
|
|
||
| return score; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| package com.javarush.morozov.core; | ||
|
|
||
| import com.javarush.morozov.ui.handlers.MessageHandler; | ||
|
|
||
| import javax.swing.filechooser.FileNameExtensionFilter; | ||
| import java.io.File; | ||
| import java.io.IOException; | ||
| import java.nio.file.Files; | ||
| import java.nio.file.Paths; | ||
|
|
||
| public class FileHandler { | ||
| private static final long MAX_FILE_SIZE = 10 * 1024 * 1024; // 10 MB | ||
|
|
||
| public String readTextFile(File file) throws IOException { | ||
| if (!file.exists()) { | ||
| throw new IOException("Файл не существует"); | ||
| } | ||
|
|
||
| if (file.length() > MAX_FILE_SIZE) { | ||
| throw new IOException("Файл слишком большой (макс. " + MAX_FILE_SIZE/1024/1024 + " МБ)"); | ||
| } | ||
|
|
||
| if (!file.canRead()) { | ||
| throw new IOException("Нет прав на чтение файла"); | ||
| } | ||
|
|
||
| String content = Files.readString(Paths.get(file.getPath())); | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Если выделить три переменных то скорость не пострадает, а читать проще |
||
|
|
||
| if (content.trim().isEmpty()) { | ||
| throw new IOException("Файл пуст"); | ||
| } | ||
|
|
||
| return content; | ||
| } | ||
|
|
||
| public void saveTextFile(File file, String content) throws IOException { | ||
| if (file.exists() && !file.canWrite()) { | ||
| throw new IOException("Нет прав на запись в файл"); | ||
| } | ||
|
|
||
| if (file.exists()) { | ||
| if (!MessageHandler.confirmFileOverwrite()) { | ||
| throw new IOException("Сохранение отменено"); | ||
| } | ||
| } | ||
|
|
||
| Files.writeString(file.toPath(), content); | ||
| } | ||
|
|
||
| public static FileNameExtensionFilter getTextFileFilter() { | ||
| return new FileNameExtensionFilter("Текстовые файлы (*.txt)", "txt"); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,98 @@ | ||
| package com.javarush.morozov.ui; | ||
|
|
||
| import com.javarush.morozov.core.CaesarCipher; | ||
| import com.javarush.morozov.core.FileHandler; | ||
| import com.javarush.morozov.ui.listeners.*; | ||
|
|
||
| import javax.swing.*; | ||
| import java.awt.*; | ||
|
|
||
| public class MainWindow extends JFrame { | ||
| private JTextArea inputTextArea; | ||
| private JTextArea outputTextArea; | ||
| private JButton encryptButton; | ||
| private JButton decryptButton; | ||
| private JButton bruteForceButton; | ||
| private JButton loadFileButton; | ||
| private JButton saveFileButton; | ||
| JComboBox<CaesarCipher.Language> languageComboBox; | ||
|
|
||
|
|
||
| public MainWindow() { | ||
| super("Шифр цезаря"); | ||
| setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); | ||
| setSize(800, 600); | ||
| setLayout(new BorderLayout()); // автоматическое управление расположением компонентов внутри контейнера | ||
|
|
||
| initUI(); | ||
| setupListeners(); | ||
| } | ||
|
|
||
| /** | ||
| * Инициализация UI заданными компонентами. | ||
| */ | ||
| private void initUI() { | ||
| JPanel topPanel = new JPanel(new BorderLayout()); | ||
|
|
||
| JPanel headerPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); | ||
| languageComboBox = new JComboBox<>(CaesarCipher.Language.values()); | ||
| languageComboBox.setSelectedItem(CaesarCipher.Language.RUSSIAN); | ||
| headerPanel.add(new JLabel("Символы шифровки:")); | ||
| headerPanel.add(languageComboBox); | ||
| topPanel.add(headerPanel, BorderLayout.NORTH); | ||
|
|
||
| JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 10, 10)); | ||
| encryptButton = new JButton("Зашифровать"); | ||
| decryptButton = new JButton("Расшифровать"); | ||
| bruteForceButton = new JButton("Brute Force"); | ||
| loadFileButton = new JButton("Загрузить файл"); | ||
| saveFileButton = new JButton("Сохранить в файл"); | ||
|
|
||
| buttonPanel.add(loadFileButton); | ||
| buttonPanel.add(encryptButton); | ||
| buttonPanel.add(decryptButton); | ||
| buttonPanel.add(bruteForceButton); | ||
| buttonPanel.add(saveFileButton); | ||
| topPanel.add(buttonPanel, BorderLayout.CENTER); | ||
|
|
||
| inputTextArea = new JTextArea(); | ||
| outputTextArea = new JTextArea(); | ||
| outputTextArea.setEditable(false); | ||
|
|
||
| JScrollPane inputScrollPane = new JScrollPane(inputTextArea); | ||
| JScrollPane outputScrollPane = new JScrollPane(outputTextArea); | ||
|
|
||
| JPanel textPanel = new JPanel(new GridLayout(1, 2, 10, 10)); | ||
| textPanel.add(inputScrollPane); | ||
| textPanel.add(outputScrollPane); | ||
|
|
||
| add(topPanel, BorderLayout.NORTH); | ||
| add(textPanel, BorderLayout.CENTER); | ||
| } | ||
|
|
||
| /** | ||
| * Установка прослушиваний при нажатии на кнопки | ||
| */ | ||
| private void setupListeners() { | ||
| FileHandler handler = new FileHandler(); | ||
| CaesarCipher cipher = new CaesarCipher(getSelectedLanguage()); | ||
|
|
||
| LoadFileButtonListener loadListener = new LoadFileButtonListener(inputTextArea, outputTextArea, handler); | ||
| SaveFileButtonListener saveListener = new SaveFileButtonListener(outputTextArea, handler); | ||
| EncryptButtonListener encryptListener = new EncryptButtonListener(inputTextArea, outputTextArea, cipher); | ||
| DecryptButtonListener decryptListener = new DecryptButtonListener(inputTextArea, outputTextArea, cipher); | ||
| BruteForceButtonListener bruteForceListener = new BruteForceButtonListener(inputTextArea, outputTextArea, cipher); | ||
|
|
||
| loadFileButton.addActionListener(loadListener); | ||
| saveFileButton.addActionListener(saveListener); | ||
| encryptButton.addActionListener(encryptListener); | ||
| decryptButton.addActionListener(decryptListener); | ||
| bruteForceButton.addActionListener(bruteForceListener); | ||
| languageComboBox.addActionListener(_ -> cipher.setLanguage(getSelectedLanguage())); | ||
|
|
||
| } | ||
|
|
||
| private CaesarCipher.Language getSelectedLanguage() { | ||
| return (CaesarCipher.Language) languageComboBox.getSelectedItem(); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| package com.javarush.morozov.ui.handlers; | ||
|
|
||
| import javax.swing.*; | ||
|
|
||
| public class MessageHandler { | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Все методы статические, значит нужен приватный конструктор. |
||
| public static void showErrorDialog(String message) { | ||
| JOptionPane.showMessageDialog( | ||
| null, | ||
| message, | ||
| "Ошибка", | ||
| JOptionPane.ERROR_MESSAGE | ||
| ); | ||
| } | ||
|
|
||
| public static void showSuccessDialog(String message) { | ||
| JOptionPane.showMessageDialog( | ||
| null, | ||
| message, | ||
| "Успех", | ||
| JOptionPane.INFORMATION_MESSAGE | ||
| ); | ||
| } | ||
|
|
||
| public static boolean confirmFileOverwrite() { | ||
| return JOptionPane.showConfirmDialog( | ||
| null, | ||
| "Файл уже существует. Перезаписать?", | ||
| "Подтверждение", | ||
| JOptionPane.YES_NO_OPTION | ||
| ) == JOptionPane.YES_OPTION; | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
import?