package com.mattrixwv.cipherstream.monosubstitution; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.mattrixwv.cipherstream.exceptions.InvalidInputException; /** * Implements the Atbash cipher, a simple substitution cipher where each letter of the alphabet is mapped to its reverse. * For example, 'A' is mapped to 'Z', 'B' to 'Y', and so on. * This class provides methods to encode and decode strings using the Atbash cipher. * *
* The Atbash cipher is symmetric, meaning that encoding and decoding are the same operation. *
*/ public final class Atbash{ private static final Logger logger = LoggerFactory.getLogger(Atbash.class); //?Fields /** Holds the string that needs encoded or decoded */ protected String inputString; /** The encoded/decoded string */ protected String outputString; //?Settings /** Persist capitals in the output string */ protected boolean preserveCapitals; /** Persist whitespace in the output string */ protected boolean preserveWhitespace; /** Persist symbols in the output string */ protected boolean preserveSymbols; /** * Encodes the input string using the Atbash cipher. */ protected void encode(){ logger.debug("Encoding"); StringBuilder output = new StringBuilder(); //Step through every element in the inputString and shift it the correct amount for(int cnt = 0;cnt < inputString.length();++cnt){ char currentChar = inputString.charAt(cnt); logger.debug("Encoding char {}", currentChar); //Decode if the letter is alphabetic if(Character.isAlphabetic(currentChar)){ //Use either uppercase or lowercase for the base //(letterbase + 25 - (currentChar - letterBase)) if(Character.isUpperCase(currentChar)){ logger.debug("Encoding uppercase"); output.append((char)(155 - currentChar)); } else{ logger.debug("Encoding lowercase"); output.append((char)(219 - currentChar)); } } //Keep any punctuatio/whitespace the way it is else{ logger.debug("Appending symbol"); output.append(currentChar); } } //Return the output outputString = output.toString(); logger.debug("Saving output string '{}'", outputString); } /** * Sets and sanitizes the input string according to the preservation settings. * * @param inputString the string to be processed * @throws InvalidInputException if the input string is null or blank after processing */ protected void setInputString(String inputString) throws InvalidInputException{ if(inputString == null){ throw new InvalidInputException("Input cannot be null"); } logger.debug("Original input string '{}'", inputString); if(!preserveCapitals){ logger.debug("Removing case"); //Convert all letters to lowercase inputString = inputString.toUpperCase(); } if(!preserveWhitespace){ logger.debug("Removing whitespace"); //Remove all characters except capital letters inputString = inputString.replaceAll("\\s", ""); } if(!preserveSymbols){ logger.debug("Removing symbols"); //Remove all non-alpha numeric and whitespace symbols inputString = inputString.replaceAll("[^a-zA-Z\\s]", ""); } //Save the string this.inputString = inputString; logger.debug("Cleaned input string '{}'", inputString); if(this.inputString.isBlank()){ throw new InvalidInputException("Input must contain at least 1 character"); } } //?Constructor /** * Constructs a new {@code Atbash} instance with default settings: * capitals, symbols, and whitespace are not preserved. */ public Atbash(){ reset(); preserveCapitals = false; preserveWhitespace = false; preserveSymbols = false; } /** * Constructs a new {@code Atbash} instance with specified settings for preserving capitals, whitespace, and symbols. * * @param preserveCapitals whether to preserve capital letters in the output * @param preserveWhitespace whether to preserve whitespace in the output * @param preserveSymbols whether to preserve symbols in the output */ public Atbash(boolean preserveCapitals, boolean preserveWhitespace, boolean preserveSymbols){ reset(); this.preserveCapitals = preserveCapitals; this.preserveWhitespace = preserveWhitespace; this.preserveSymbols = preserveSymbols; } /** * Encodes the provided input string using the Atbash cipher and returns the encoded result. * * @param inputString the string to be encoded * @return the encoded string * @throws InvalidInputException if the input string is invalid */ public String encode(String inputString) throws InvalidInputException{ //Make sure everything is empty before you begin reset(); setInputString(inputString); encode(); return outputString; } /** * Decodes the provided input string using the Atbash cipher and returns the decoded result. * Since the Atbash cipher is symmetric, this method performs the same operation as encoding. * * @param inputString the string to be decoded * @return the decoded string * @throws InvalidInputException if the input string is invalid */ public String decode(String inputString) throws InvalidInputException{ return encode(inputString); } //?Getters /** * Returns the current input string. * * @return the input string */ public String getInputString(){ return inputString; } /** * Returns the current output string. * * @return the output string */ public String getOutputString(){ return outputString; } /** * Resets all fields to their default values. */ public void reset(){ logger.debug("Resetting fields"); inputString = ""; outputString = ""; } }