This question already has answers here:
Java, How to implement a Shift Cipher (Caesar Cipher)
(7 answers)
Closed last year.
I am trying to make a game where a paragraph of text is “encrypted” using a simple substitution cipher, so for example, all A's will be F's and B's will be G's an so on.
The idea is that the user/player will need to try to guess the famous quote by trying to decrypt the letters. So the screen shows them a blank space with a letter A and they have to figure out it's really an F that goes in the place within the string.
I've not got very far, basically I can manually change each letter using a for loop, but there must be an easier way.
import java.util.Scanner;
import java.util.Random;
public class cryptogram {
public static void main(String[] args) {
char[] alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
for (char i = 0; i <alphabet.length; i++) {
if (alphabet[i] == 'B') {
alphabet[i] = 'Z';
}
}
System.out.println(alphabet);
}
}
Substitution
A "substitution" workflow might look something like...
public class Main {
public static void main(String[] args) {
new Main().substitution();
}
public void substitution() {
char[] lookup = "ABCDEFGHIJKLMNOPQRSTUVWXYZ ".toCharArray();
char[] substitution = " FGHIJKLMNOPQRSTUVWXYZABCDE".toCharArray();
String text = "This is a test";
StringBuilder builder = new StringBuilder(text.length());
for (char value : text.toCharArray()) {
int index = indexOf(value, lookup);
builder.append(substitution[index]);
}
String encypted = builder.toString();
System.out.println(text);
System.out.println(encypted);
builder = new StringBuilder(text.length());
for (char value : encypted.toCharArray()) {
int index = indexOf(value, substitution);
builder.append(lookup[index]);
}
System.out.println(builder.toString());
}
protected static int indexOf(char value, char[] array) {
char check = Character.toUpperCase(value);
for (int index = 0; index < array.length; index++) {
if (check == array[index]) {
return index;
}
}
return -1;
}
}
Which will output something like...
This is a test
XLMWEMWE EXIWX
THIS IS A TEST
Now, obviously, this only supports upper-cased characters and does not support other characters like numbers or punctuation (like ! for example). The above example will also crash if the character can't be encoded, it's just an example of an idea after all 😉
A "different" approach
Now, char is a peculiar type, as it can actually be treated as an int. This has to do with how text is encoded by computers, see ASCII Table for an example.
This means that we can do mathematical operations on it (+/-). Now, assuming that we only want to deal with "displayable" characters, this gives us a basic range of 32-126 (you could also have the extended range from 128-255, but lets keep it simple for now)
With this is hand, we could actually do something like...
public class Main {
public static void main(String[] args) {
new Main().encode();
}
private static final int MIN_RANGE = 32;
private static final int MAX_RANGE = 127;
public void encode() {
String text = "This is a test";
String encoded = encode(text, 4);
System.out.println(text);
System.out.println(encoded);
System.out.println(encode(encoded, -4));
}
protected String encode(String value, int offset) {
StringBuilder sb = new StringBuilder(value.length());
for (char c : value.toCharArray()) {
sb.append(encode(c, offset));
}
return sb.toString();
}
protected char encode(char value, int offset) {
char newValue = (char)(value + offset);
if (newValue < MIN_RANGE) {
newValue = (char)(MAX_RANGE - (MIN_RANGE - newValue));
} else if (newValue > MAX_RANGE) {
newValue = (char)((newValue - MAX_RANGE) + MIN_RANGE);
}
return newValue;
}
}
Which outputs...
This is a test
Xlmw$mw$e$xiwx
This is a test
As you can see, decoding is just passing the encoded text with offset in the opposite direction. It's also easier to change the offset if you want to change the encoding process
Related
I want to write a library to generate a String from a given regex. However, I run into a problem, if the regex uses a negated character class, like [^a-z]. In this case, I have to place a character into the generated String that does not match [a-z]. Also, I want to be able to define a set of characters that are used preferably, e.g. the set of printable characters.
Question
How do I generate a random character that is not contained in a given array/collection? How can I prefer groups of characters in this process?
An existing function in the libraries would be great, however I wasn't able to find one.
Here is my approach to solve the problem, however I wonder if there is a better algorithm. Also, my algorithm does not prefer a given set of characters, mainly because I do not know how to check if a character is printable or how I get an array/collection/iterable of printable characters.
private void run() {
int i = 1024;
System.out.println(getFirstLegalChar(createExampleIllegalCharArray(i)));
System.out.println((char) i);
}
private char getFirstLegalChar(char[] illegalCharArray) {
for (int i = 0; true; i++) {
if (!contains(illegalCharArray, (char) i)) {
return (char) i;
}
}
}
private char[] createExampleIllegalCharArray(int size) {
char[] illegalCharArray = new char[size];
for (int i = 0; i < illegalCharArray.length; i++) {
illegalCharArray[i] = (char) i;
}
return illegalCharArray;
}
private boolean contains(char[] charArray, char c) {
for (int j = 0; j < charArray.length; j++) {
if (charArray[j] == c) {
return true;
}
}
return false;
}
you can check the list of printable and non printable characters at
Juniper.
i have checked few things and come-up with one solution you can check
public static void main(String[] args) {
final char RECORD_SEPARATOR = 0x1e;
final char END_OF_TEXT = 0x03;
System.out.println(isPrintableChar(RECORD_SEPARATOR));
System.out.println(isPrintableChar(END_OF_TEXT));
System.out.println(isPrintableChar('a'));
}
public static boolean isPrintableChar( char c ) {
Character.UnicodeBlock block = Character.UnicodeBlock.of( c );
return (!Character.isISOControl(c)) &&
c != KeyEvent.CHAR_UNDEFINED &&
block != null &&
block != Character.UnicodeBlock.SPECIALS;
}
i got the output as
false
false
true
I need help with decompressing method. I have a working Compress method. Any suggestions as far as what I need to consider? Do I need parseInt or else....? Appreciate the advice. Here is what I have so far. If s = "ab3cca4bc", then it should return "abbbccaaaabc", for example of decompress.
class RunLengthCode {
private String pText, cText;
public RunLengthCode () {
pText = "";
cText = "";
}
public void setPText (String newPText) {
pText = newPText;
}
public void setCText (String newCText) {
cText = newCText;
}
public String getPText () {
return pText;
}
public String getCText () {
return cText;
}
public void compress () { // compresses pText to cText
String ans = "";
for (int i = 0; i < pText.length(); i++) {
char current = pText.charAt(i);
int cnt = 1;
String temp = "";
temp = temp + current;
while (i < pText.length() - 1 && (current == pText.charAt(i + 1))) {
cnt++;
i++;
temp = temp + current;
}
if (cnt > 2) {
ans = ans + current;
ans = ans + cnt;
}
else
ans = ans + temp;
setCText(ans);
}
}
public void decompress () {
}
}
public class {
public static void main(String [] args) {
Scanner in = new Scanner(System.in);
RunLengthCode myC = new RunLengthCode();
String pText, cText;
System.out.print("Enter a plain text consisting of only lower-case alphabets and spaces:");
pText = in.nextLine();
myC.setPText(pText);
myC.compress();
System.out.println(pText+" => "+myC.getCText());
System.out.print("Enter a compressed text consisting of only lower-case alphabets, spaces and digits:");
cText = in.nextLine();
myC.setCText(cText);
myC.decompress();
System.out.println(cText+" => "+myC.getPText());
}
}
You could create break the string into regx groups and combine them.
The following pattern works
(([A-Za-z]+[\d]*))
This will break your string "ab3cca4bc" into groups of
"ab3", "cca4", "bc"
So in a loop if the last character is a digit, you could multiply the character before it that many times.
Ok, so you've got an input string that looks like ab3cca4bc
1.) Loop over the length of the input String
2.) During each loop iteration, use the String.charAt(int) method to pick up the individual character
3.) The Character class has an isDigit(char) function that you can use to determine if a character is a number or not. You can then safely use Integer.parseInt(String) (you can use myChar+"" to convert a char into a String)
4.) If the char in question is a number, then you'll need to have an inner loop to repeat the previous character the correct number of times. How will you know what the last character was? Maybe have a variable that's instantiated outside the loop that you update each time you add a character on the end?
I have come up with a solution for removing punctuation from a String in Java.Need to convert this into a recursive method.I would be thankful if someone can help me to solve this.
The code is as below:
public class punctuationRemove {
//private static String punc = "[][(){},.;!?<>%]";
static StringBuilder sb = new StringBuilder();
static char[] punc = "',.;!?(){}[]<>%".toCharArray();
public static void main(String[] args){
String s = "Hello!, how are you?";
System.out.println(removePuntuation(s));
}
public static String removePuntuation(String s)
{
String tmp;
boolean fl=true;
for(int i=0;i<s.length()-1;i++)
{
fl=true;
char strChar=s.charAt(i);
for (char badChar : punc)
{
if (badChar == strChar)
{
fl=false;
break;
}
}
if(fl)
{
sb.append(strChar);
}
}
return sb.toString();
}
}
Recursion usually has two parts to it:
A base case in which all recursion stops and a result is returned, and
An iterative step in which recursion continues.
How does one recursively examine each character of a String? They only look at the first character and send the substring from 1 to the end of it off to a recursive call.
As an example:
public String splitRecursive(String s) {
if(!s.isEmpty()) {
return s.charAt(0) + splitRecursive(s.substring(1));
} else {
return "";
}
}
Let's think about that for a moment - so long as the string isn't empty (i.e. base case), then I should take the first character I get and append that to the result of another call (i.e. iterative step), which takes the substring from 1 to however many characters are left. If it is empty, I just return the empty string.
This skeleton piece of code is actually 3/4ths of what you need to work out your problem. You need to augment it to insepct the character to see if it is one of your punctuation characters you've already isolated.
Consider your iterative step: if you see punctuation, what should you do? If you don't see punctuation, what should you do? I leave the rest as an exercise to the reader.
I think this would help you,
public class RemovePunctuations {
public static int i = 0;
public static void main(String[] args){
String s = "Hello!, how are you?";
System.out.println(removePuntuation(s));
}
Using Recursion,
public static String removePuntuation(String s){
char [] charArray = s.toCharArray();
if(!Character.isLetter(charArray[i]) && !Character.isSpaceChar(charArray[i])){
s = s.replace(String.valueOf(charArray[i]), "");
i--;
}
i++;
if(i<s.length())
return removePuntuation(s);
return s;
}
}
You can get the same result from the following way without using recursion,
public static String removePuntuation(String s){
char [] charArray = s.toCharArray();
for (int i = 0; i < charArray.length; i++) {
if(!Character.isLetter(charArray[i]) && !Character.isSpaceChar(charArray[i])){
s = s.replace(String.valueOf(charArray[i]), "");
}
}
return s;
}
Language : Java
Key Notes: *Needs to loop through a String using either a For loop or While loop
*It removes the duplicate letter(s) of the String and returns the word without the dupilcates.
Eg: The string is HELLO - The method then loops through and removes any duplicates, in this case " L " and returns in the end HELO
i have this so far
private String removeAnyDuplicates(String userWord)
{
//Code goes here?
return "" ; // Need to return the new string
}
You can do that with regular expressions. e.g.:
private static final Pattern REGEX_PATTERN =
Pattern.compile("(.)\\1*");
public static void main(String[] args) {
String input = "HELLO, AABBCC";
System.out.println(
REGEX_PATTERN.matcher(input).replaceAll("$1")
); // prints "HELO, ABC"
}
I'm assuming that removing duplicates means that the result contains at most one occurrence of any character. (Some of the other answers assume that adjacent duplicates only need to be reduced to single occurrences.) The basic algorithm would be:
initialize the result to the empty string
loop through each character of the input and if the character is not already present in the result, append it to the result
return the result
A naive (and very inefficient) implementation would be:
private String removeAnyDuplicates(String userWord)
{
String result = "";
for (int i = 0; i < userWord.length(); ++i) {
char c = result.charAt(i);
if (result.indexOf(c) < 0) {
// negative index indicates not present
result += String.valueOf(c);
}
}
return result;
}
This has two major sources of inefficiency: it creates many intermediate String objects and it has to scan the entire result so far for each character of the input. These problems can be solved by using some other built-in Java classes—a StringBuilder to more efficiently accumulate the result and a Set implementation to efficiently record and test which characters have already been seen:
private String removeAnyDuplicates(String userWord)
{
int len = userWord.length();
StringBuilder result = new StringBuilder(len);
Set<Character> unique = new HashSet<Character>();
for (int i = 0; i < len; ++i) {
char c = result.charAt(i);
// try to add c to set of unique characters
if (unique.add(c)) {
// if it succeeds, this is the first time seeing c
result.append(c);
}
}
return result.toString();
}
private String removeAnyDuplicates(String userWord)
{
CharSequence inputStr = userWord;
int length = inputStr.length();
Set<Character> uniqueChars = new HashSet<Character>();
for(int i=0; i < length; ++i) {
uniqueChars.add(inputStr.charAt(i));
}
return uniqueChars.size() >= 3;
}
check out this answer
Convert the string to an array of char, and store it in a LinkedHashSet. That will preserve your ordering, and remove duplicates.
Like this:
private static String removeAnyDuplicates(String userWord)
{
char[] chars = userWord.toCharArray();
Set<Character> charSet = new LinkedHashSet<Character>();
for (char c : chars) {
charSet.add(c);
}
StringBuilder sb = new StringBuilder();
for (Character character : charSet) {
sb.append(character);
}
return sb.toString();
}
Remember:
import java.util.LinkedHashSet;
import java.util.Set;
You can try this
public static void main(String args[]){
System.out.println(removeAnyDuplicates("HELLO"));
}
private static String removeAnyDuplicates(String userWord)
{
char[] arr=userWord.toCharArray();
List<String> list=new ArrayList<>();
for(int i=0;i<arr.length;i++){
if(!list.contains(String.valueOf(arr[i]))){
list.add(String.valueOf(arr[i]));
}
}
return list.toString().replaceAll("\\[|\\]|\\,","") ;
}
Try this one liner:
private String removeAnyDuplicates(String userWord) {
return userWord.replaceAll("(.)\\1+", "$1");
}
This uses a regular expression to find repeated (2 or more) letters and replaces them with a single instance of the letter.
It is unclear if "repeated" means appearing immediately after or anywhere after. For anywhere, use this:
private String removeAnyDuplicates(String userWord) {
return userWord.replaceAll("(.)(?=.*\\1)", "");
}
Every other question I have seen in my book I had at least some understanding of what the book was asking but this one I have no idea on how to approach it. It goes:
"Write a method called padString that accepts two parameters: a String and an integer representing a length. For example,
padString ("hello", 8)
should return "hello " (that's three spaces in there at the end). If the string's length is already at least as long as the length parameter, your method should return the original string. For example,
padString ("congratulations", 10)
should return "congratualtions".
I have no idea on how to approach this being pretty new to Java. This is supposed to be a beginner's homework so I suppose the method is very simple. Please show me how to do this and explain the steps if you can. Please and Thank you to whoever helps.
So your function should do something like this:
Determine number of padding characters required.
Need <= 0 padding characters? return input string
Otherwise, create a string with required padding characters, then return input string + required padding characters
You can find a string's length with the .length() method.
You could use the printf method in System.out (needs Java 1.6 or later, it's a new PrintStream method). Hake a look at an interesting example below, where the output is (specified below code). The padding is specified in the printf argument as 30, and is justified left:
package pft;
public class PrintfTest {
public static void main(String[] args) {
int padding = 30;
String s = "hi!";
System.out.printf("'%0$-" + padding + "s'", s);
}
}
prints: 'hi! '.
Taking it piece at a time (and without giving you all the code):
"Write a method called padString that
accepts two parameters: a String and
an integer representing a length."
public static ??? padString(String str, int len)
"For example,padString("hello", 8)
should return "hello"."
public static String padString(String str, int len)
{
throw new Error("not implemented yet");
}
"If the string's length is already at
least as long as the length parameter,
your method should return the original
string. For example,
padString("congratulations", 10)
should return "congratualtions"."
EDIT: you fixed the question...
public static String padString(String str, int len)
{
// if the str.length is greater than len
// return str
// this next part is very simple, not a very good way but gets you
// started. Once you have it working look at StringBuilder and .append.
// int val = the difference in length between the two strings
// for i = 0; i is less than val; i++
// str += " ";
// return str
}
public class PadString {
public static void main(String[] args) {
String str = "hello";
str = padStr(str, 10, ' ');
}
static String padStr(String s, int len, char c) {
int n = len - s.length();
if (n <= 0)
return s;
StringBuilder b = new StringBuilder(s);
for (int i = 0; i < n; i++)
b.append(c);
return b.toString();
}
}
Even thought this post is about 2 years old. I just recently had this
question for a homework. And I thought it might help other beginners
that might come across this problem to see a simpler way of solving
this problem.
One that will probably be more in line to where they are in their
beginner java course assuming they are getting this around the same
time that I did.
Of course you should remove the dashes in the loop and use spaces to
get credit for the assignment, that is there just to show you that it
works.
public class ex3_11_padString {
public static void main(String[] args) {
padString("hello",10);
}
public static String padString( String s, int len) {
int s_length = s.length();
int diff = len - s_length;
String newString;
newString = "";
for (int x = 0 ; x < diff; x++) {
newString += "-";
}
newString = newString + s;
return new String;
}
}
You may want to take a look at Java's String class documentation. Look for a method that returns the length of the string...
public static String padString(String str, int len)
{
int lengt=str.length();
if(lengt==len||lengt>len)
return str;
else if(lengt<len){
String spacstr="";
for(var i=lengt;i<len;i++){
spacstr+="$";
}
return str+spacstr;
}
}
///more generalized by accepting pad character
public static String padString(String str, int len,String padChar)
{
int lengt=str.length();
if(lengt==len||lengt>len)
return str;
else if(lengt<len){
String spacstr="";
for(var i=lengt;i<len;i++){
spacstr+=padChar;
}
return str+spacstr;
}
}
public String padString (String s, int padding) {
return String.format("%-" + padding + "s", s);
}
This is the better solution for me. Taken from the comment of #John C, with the "%-" added.
Sorry #John C I cannot edit your comment or add one below yours.