Algorithm to generate random string with harsh restrictions - Java - java

I'm trying to make a program to generate a random account name for the user. The user will hit a button and it will copy the account name to his clipboard. The GUI part of it is working but I just can't think of the best way to handle random generation of a String.
Allowed characters in the username: A-Z a-z _
No numbers, no other symbols, and no two of the same character in a row can occur.
Must be of length six.
My idea:
create an array of characters:
[ _, a, b, c, d ... etc ]
Generate a random integer between 0 and array.length - 1
and pick the letter in that slot.
Check the last character to be added into the output String,
and if it's the same as the one we just picked, pick again.
Otherwise, add it to the end of our String.
Stop if the String length is of length six.
Is there a better way? Perhaps with regex? I have a feeling the way I'm thinking of doing it here is really bad.

I don't see anything wrong with your proposed algorithm (except you need to handle the first character you add without checking if you've already added it). You might also extract it to a static method and use a Random like,
static Random rand = new Random();
static String getPassword(String alphabet, int len) {
StringBuilder sb = new StringBuilder(len);
while (sb.length() < len) {
char ch = alphabet.charAt(rand.nextInt(alphabet.length()));
if (sb.length() > 0) {
if (sb.charAt(sb.length() - 1) != ch) {
sb.append(ch);
}
} else {
sb.append(ch);
}
}
return sb.toString();
}
Then you could call it with something like,
public static void main(String[] args) {
StringBuilder alphabet = new StringBuilder();
for (char ch = 'a'; ch <= 'z'; ch++) {
alphabet.append(ch);
}
alphabet.append(alphabet.toString().toUpperCase()).append('_');
String pass = getPassword(alphabet.toString(), 6);
System.out.println(pass);
}

Related

letter change, what am I doing wrong?

So im trying the following challenge:
Using the Java language, have the function LetterChanges(str) take the str parameter being passed andmodify it using the following algorithm. Replace every letter in the string with the letter following it in thealphabet (ie. c becomes d, z becomes a). Then capitalize every vowel in this new string (a, e, i, o, u) and finally return this modified string.
This is my code
class LetterChange {
public static String LetterChanges(String str) {
String alphabet = "AbcdEfghIjklmnOpqrstUvwxyz";
char currentChar,letter;
int i = 0;
while (i < str.length())
{
currentChar = str.charAt(i);
for(int x = 0; x < alphabet.length(); x++)
{
letter = alphabet.charAt(x);
if (currentChar == letter){
str = str.replace(currentChar,alphabet.charAt(x+1));
i++;
}
}
}
when I run it it is returning the last char in string +1 letter in alphabet. for example if i was to run "bcd" it returns "EEE". I dont understand why its replacing all chars with the result of the loop for the last char.
When you go through the loop the first time you get
"bcd"--> "ccd"
Now, str.replace will turn this into "ddd" on next turn, then "EEE".
I.e., replace replaces every occurrence on each turn.
It is true that debugging it in the IDE will help you in the future!
Also, what if you had a lowercase vowel in your string?
public class Alphabet {
public static String LetterChanges(String str) {
String alphabet = "AbcdEfghIjklmnOpqrstUvwxyz";
char[] string = str.toLowerCase().toCharArray();
for (int i=0; i < string.length; i++) {
char d = alphabet.charAt(((alphabet.toLowerCase().indexOf(string[i]))+1) % 26);
string[i]=d;
}
return new String(string);
}
public static void main(String[] args) {
System.out.println(Alphabet.LetterChanges("aabb"));
}
}
alphabet.charAt(
((alphabet.toLowerCase().indexOf(string[i]))
+1) % 26)
1) use toLowerCase on the input and your string map to eliminate case problems
2) find character at index+1 in string map 'alphabet', treating it as a circular buffer using a modulus that takes z to a.
index 25 (z) + 1 == 26 --> 0 (A) because 26 is 0 mod 26 while index 0(A) + 1 = 1 --> 1 mod 26. It is only necessary to wrap the z to A while not changing the other 25 indices and is more efficient than branching with an "if" statement.
Does this solution help?
public static String letterChanges(String str) {
String alphabet = "AbcdEfghIjklmnOpqrstUvwxyz";
StringBuilder stringBuilder = new StringBuilder();
for (char letter : str.toCharArray()) {
if (alphabet.contains(Character.toString(letter))) {
int index = alphabet.indexOf(letter) + 1;
if (index >= 26) {
index = 0;
}
stringBuilder.append(alphabet.charAt(index));
}
}
return stringBuilder.toString();
}
The previous solution was hard to follow, so it's difficult to explain why it wasn't working without debugging through it to see where it goes wrong. It was easier to use a for-each loop to go through the str parameter and find matches using Java's provided methods like .indexOf and .charAt.
Also, Java uses lower camel case method naming, letterChanges instead of LetterChanges :)
Let me know if you have any questions.
You are getting that result because on every replacing you are re-setting the input string. I recommend you:
Better try with two different variables: Let the input variable be unmodified, and work on the output one.
Since strings are unmodifiable -as you already know- better declare them as arrays of char.
For the shake of optimization, base your algorithm on one single loop, which will iterate over the characters of the input string. For each character, decide if it is alphabetic or not, and in case it is, what character should it be replaced with.

Caesar Cipher With Space characters left unchanged

I'm trying to let the encryption function ignore the white spaces and the symbols between words from the UserInput. Should I use isWhitespace or what? and how to implement that?
The output for this program is totally correct, it shifts each letter to the next 7 one. but it doesn't accept shifting 2 words separated by space or coma.
I'm new into Java stunning world & I'm really enjoying it! Hence this's my 3rd week since I began.
import java.util.Scanner;
public class Test_Cipher{
public static final String ALPHABET = "abcdefghijklmnopqrstuvwxyz";
public static String encrypt(String plainText, int shiftKey) {
plainText = plainText.toLowerCase();
String cipherText = "";
for (int i = 0; i < plainText.length(); i++) {
int charPosition = ALPHABET.indexOf(plainText.charAt(i));
int keyVal = (shiftKey + charPosition) % 26;
char replaceVal = ALPHABET.charAt(keyVal);
cipherText += replaceVal;
}
return cipherText;
}
}
There is two ways of doing this: either create a positive match for the character or a negative one. In the positive match variant you first check if plainText.charAt(i) is a character that you want to keep, and in that case add it to the cipherText and continue with the loop.
In the other you can check if indexOf returns -1 indicating that the alphabet doesn't contain the character. In that case you do the same thing: add it and continue. This is the common method I've seen for the classic Ceasar "play" cipher:
// introduce a local variable, you don't want to perform charAt twice
char c = plainText.charAt(i);
int charPosition = ALPHABET.indexOf(c);
// if charPositions is -1 then it is not found
if (charPosition == -1) { // or define a constant NOT_FOUND = -1
cipherText += c;
// continue with the for loop
continue;
}

Char replacement (without using replace)

This code is a series of tasks, the first is it replace all 'F' in sentence string to a 'f' without using the .replace() method. Which i've done, then after that I'm supposed to replace all the 'f's to blanks, which I sort of done but for some reason all my capital 'F's change to a weird square. Any ideas? I know it's basic code but baby steps.
Here is my weird output: "There was a isherman named []isher who ished or some ish in a issure; till a ish with a grin, pulled the isherman in. Now they’re ishing the issure or []isher."
Thanks! Rob.
public static void main(String[] args) {
// orginal string sentence
String sentence = ("There was a fisherman named Fisher who fished for some fish in a fissure; till a fish with a grin, pulled the fisherman in. Now they’re fishing the fissure for Fisher. ");
// data
char[] originalArray = sentence.toCharArray();
int i = 0;
int sLength = sentence.length();
int positionArray[];
// combining an int to the array position
positionArray = new int[sLength];
/* while loop to check the position of any 'F' or 'f' characters in sentence and identifying it's array position*/
while (i < sLength) {
char charAt = sentence.charAt(i);
if (charAt == 'F') {
originalArray[i] = 0;
positionArray[i] = 1;
}
i++;
}
//redeclaring int i to 0 for the new array
i = 0;
//reassigning the character 'F' or 'f' to just 'f to 'sentence'
sentence = new String(originalArray);
char[] newArray = sentence.toCharArray();
while (i < sLength) {
if (positionArray[i] == 1) {
newArray[i] = 'f';
}
i++;
//redeclaring int i to 0 for the (part e)
i = 0;
//removing every occurance of 'f' (part e)
while (i < sLength) {
if (newArray[i] == 'f' ) {
newArray[i] = ' ';
}
i++;
//printing to console
}
sentence = new String(newArray);
System.out.println(sentence);
}
}
Here is a solution using Java 8. It uses the fact that a String is a CharSequence, and that you can obtain an IntStream of either the characters or code points in it; this solution uses chars:
// Turn all 'F's into 'f's
private int bigFToSmallF(final int inputChar)
{
return 'F' == inputChar ? 'f' : inputChar;
}
// Turn all 'f's into '0's
private int smallFToZero(final int inputChar)
{
return 'f' == inputChar ? '0' : inputChar;
}
private String anyFToZeroes(final String input)
{
final StringBuilder sb = new StringBuilder(input.length());
input.chars().map(this::bigFToSmallF).map(this::smallFToZero)
.forEach(sb::appendCodePoint);
return sb.toString();
}
Plug this code into a main and you're done.
No errors for me. Works fine in win cmd and in eclipse. I had a similar problem some time ago. For me the issue was that there was an error in my installed fonts. Just some Win update has currupted something, don't know why. After I manually reinstalled my std fonts everything worked fine. Additionally to the problem also was within the "space". When I checked the hex value in debug view, the value was slightely off and so a different character was displayed.
Check your code indentation.
Your idea is correct, although is not optimized.
You've implemented 3 loops, but the last while is a inner loop.
I think you wanted to implement 3 'independent' loops, check out the brackets placement.

How to check if a string contains all the letters of the alphabet? [duplicate]

This question already has answers here:
Check if string has all the letters of the alphabet
(15 answers)
Closed 6 years ago.
I am trying to check if a string contains all the letters of the alphabet. I created an ArrayList which contains the whole alphabet. I converted the string to char array and I'm iterating through the character array, and for every character present in the ArrayList I'm removing an element from it. And in the end, I'm trying to check if the Arraylist is empty to see if all elements have been removed. That would indicate the string contains all the letters of the alphabet.
Unfortunately, the code is throwing IndexOutOfBoundsException error inside the if condition where I'm removing elements from the arraylist
List<Character> alphabets = new ArrayList<Character>();
alphabets.add('a');
alphabets.add('b');
alphabets.add('c');
alphabets.add('d');
alphabets.add('e');
alphabets.add('f');
alphabets.add('g');
alphabets.add('h');
alphabets.add('i');
alphabets.add('j');
alphabets.add('k');
alphabets.add('l');
alphabets.add('m');
alphabets.add('n');
alphabets.add('o');
alphabets.add('p');
alphabets.add('q');
alphabets.add('r');
alphabets.add('s');
alphabets.add('t');
alphabets.add('u');
alphabets.add('v');
alphabets.add('w');
alphabets.add('x');
alphabets.add('y');
alphabets.add('z');
// This is the string- I've just put a random example
String str = "a dog is running crazily on the ground who doesn't care about the world";
//Remove all the spaces
str = str.replace(" ", "");
// Convert the string to character array
char[] strChar = str.toCharArray();
for (int i = 0; i < strChar.length; i++) {
char inp = strChar[i];
if (alphabets.contains(inp)) {
alphabets.remove(inp);
}
}
if (alphabets.isEmpty())
System.out.println("String contains all alphabets");
else
System.out.println("String DOESN'T contains all alphabets");
All these solutions seem to do a lot of work for a relatively simple check, especially given Java 8's stream API:
/* Your lowercase string */.chars()
.filter(i -> i >= 'a' && i <= 'z')
.distinct().count() == 26;
Edit: For speed
If you want to end the string iteration as soon as the entire alphabet is found while still using streams, then you can keep track with a HashSet internally:
Set<Integer> chars = new HashSet<>();
String s = /* Your lowercase string */;
s.length() > 25 && s.chars()
.filter(i -> i >= 'a' && i <= 'z') //only alphabet
.filter(chars::add) //add to our tracking set if we reach this point
.filter(i -> chars.size() == 26) //filter the 26th letter found
.findAny().isPresent(); //if the 26th is found, return
This way, the stream will cease as soon as the Set is filled with the 26 required characters.
There are some (even still) more efficient solutions in terms of performance below, but as a personal note I will say to not bog yourself in premature optimization too much, where you could have readability and less effort in writing the actual code.
List.remove removes by index. Since a char can be cast to an int you are effectively removing index values that do not exist, ie char 'a' is equal to int 97. As you can see your list does not have 97 entries.
You can do alphabet.remove(alphabets.indexOf(inp));
As pointed out by #Scary Wombat(https://stackoverflow.com/a/39263836/1226744) and #Kevin Esche (https://stackoverflow.com/a/39263917/1226744), there are better alternative to your algorithm
O(n) solution
static Set<Integer> alphabet = new HashSet<>(26);
public static void main(String[] args) {
int cnt = 0;
String str = "a dog is running crazily on the ground who doesn't care about the world";
for (char c : str.toCharArray()) {
int n = c - 'a';
if (n >= 0 && n < 26) {
if (alphabet.add(n)) {
cnt += 1;
if (cnt == 26) {
System.out.println("found all letters");
break;
}
}
}
}
}
Adding to #Leon answer, creating a List and removing from it seems quite unnecessary. You could simply loop over 'a' - 'z' and do a check with each char. Additionally you are looping over the whole String to find out, if each letter is present. But the better version would be to loop over each letter itself. This can potentionally safe you a few iterations.
In the end a simple example could look like this:
// This is the string- I've just put a random example
String str = "a dog is running crazily on the ground who doesn't care about the world";
str = str.toLowerCase();
boolean success = true;
for(char c = 'a';c <= 'z'; ++c) {
if(!str.contains(String.valueOf(c))) {
success = false;
break;
}
}
if (success)
System.out.println("String contains all alphabets");
else
System.out.println("String DOESN'T contains all alphabets");
Regex is your friend. No need to use a List here.
public static void main(String[] args) {
String s = "a dog is running crazily on the ground who doesn't care about the world";
s = s.replaceAll("[^a-zA-Z]", ""); // replace everything that is not between A-Za-z
s = s.toLowerCase();
s = s.replaceAll("(.)(?=.*\\1)", ""); // replace duplicate characters.
System.out.println(s);
System.out.println(s.length()); // 18 : So, Nope
s = "a dog is running crazily on the ground who doesn't care about the world qwertyuioplkjhgfdsazxcvbnm";
s = s.replaceAll("[^a-zA-Z]", "");
s = s.toLowerCase();
s = s.replaceAll("(.)(?=.*\\1)", "");
System.out.println(s);
System.out.println(s.length()); //26 (check last part added to String) So, Yes
}
Another answer has already pointed out the reason for exception. You have misused List.remove(), as it implicitly convert char to int which it called the List.remove(int) which remove by index.
The way to solve is actually easy. You can make it call the List.remove(Object) by
alphabets.remove((Character) inp);
Some other improvements:
You should use Set instead of List in this case.
You can even use a boolean[26] to keep track of whether an alphabet has appeared
You do not need to convert your string to char array. Simply do a str.charAt(index) will give you the character at certain position.
One integer variable is enough to store this information. You can do it like this
public static boolean check(String input) {
int result = 0;
input = input.toLowerCase();
for (int i = 0; i < input.length(); i++) {
char c = input.charAt(i);
if (c >= 'a' && c <= 'z') {
result |= 1 << (input.charAt(i) - 'a');
}
}
return result == 0x3ffffff;
}
Each bit corresponds to a letter in English alphabet. So if your string contains all letters the result will be of form 00000011111111111111111111111111
How about creating
List<String> alphabets = new ArrayList <String> ();
and add values as strings
then
for (String val : alphabets) { // if str is long this will be more effecient
if (str.contains (val) == false) {
System.out.println ("FAIL");
break;
}
}
You can get rid of the exception, by changing this line in your code
char inp = strChar[i];
to
Character inp = strChar[i];
Refer https://docs.oracle.com/javase/7/docs/api/java/util/List.html#remove(java.lang.Object)
List.remove('char') is treated as List.remove('int'), which is why you are getting indexOutOfBoundsException, because it is checking the ASCII value of 'a' which is 97. Converting variable 'inp' to Character would call List.remove('Object') api.
And if you like Java 8 streams like me:
final List<String> alphabets = new ArrayList<>();
And after filling alphabets with a-z:
final String str = "a dog is running crazily on the ground who doesn't care about the world";
final String strAsLowercaseAndWithoutOtherChars = str.toLowerCase()
.replaceAll("[^a-z]", "");
final boolean anyCharNotFound = alphabets.parallelStream()
.anyMatch(t -> !strAsLowercaseAndWithoutOtherChars.contains(t));
if (anyCharNotFound) {
System.out.println("String DOESN'T contains all alphabets");
} else {
System.out.println("String contains all alphabets");
}
This converts the string to lower case (skip if you really are only looking for the small letters), removes all characters from the string which are not small letters and then checks for all members of your alphabets if they are contained in the string by using a parallel stream.
Here's another naive solution that uses String.split("") to split every character into a String[] array, then Arrays.asList() to convert that to a List<String>. You can then call yourStringAsList.containsAll(alphabet) to determine whether your String contains the alphabet:
String yourString = "the quick brown fox jumps over the lazy dog";
List<String> alphabet = Arrays.asList("abcdefghijklmnopqrstuvwxyz".split(""));
List<String> yourStringAsList = Arrays.asList(yourString.split(""));
boolean containsAllLetters = yourStringAsList.containsAll(alphabet);
System.out.println(containsAllLetters);
This approach might not be the fastest, but I think the code is a littler easier to understand than the solutions proposing loops and streams and whatnot.
Just do something like
sentence.split().uniq().sort() == range('a', 'z')
For Java 8, it could be written like:
boolean check(final String input) {
final String lower = input.toLowerCase();
return IntStream.range('a', 'z'+1).allMatch(a -> lower.indexOf(a) >= 0);
}
Convert the string to lower case or capitals. Then loop thru the equivalent ascii decimal values for A-Z or a-z and return false if not found in character array. You will have to cast the int to char.
I've thought about playing with the ASCII codes of the characters.
String toCheck = yourString.toLowerCase();
int[] arr = new int[26];
for(int i = 0; i < toCheck.length(); i++) {
int c = ((int) toCheck.charAt(i)) - 97;
if(c >= 0 && c < 26)
arr[c] = arr[c] + 1;
}
After running the loop you eventually get an array of counters, each representing a letter of alphabet (index) and it's occurrence in the string.
boolean containsAlph = true;
for(int i = 0; i < 26; i++)
if(arr[i] == 0) {
containsAlph = false;
break;
}
Character inp = strChar[i];
Use this instead of char, List remove method have 2 overloaded methods , one with object and one with int .If you pass char its been treated as the int one.

Java takes long to convert a 5 letter word to numbers

Before I start I would like to inform you that I am a total beginner to Java so excuse my uneducated mistakes. I have been trying to program an application to encrypt a message. During this process, the input gets converted to a number to allow mathematical expressions. The problem is when trying to convert. The actual code does work, but takes a rather long time to convert a 5 letter word, which is the word "Hello"( it takes around 10 seconds or so). Below is the method where the input gets converted. `
public static void encrypt(String plainText) {
Random random = new Random();
plainText =plainText.toUpperCase();
char[] storedInput = plainText.toCharArray();
int[] convertedInput = new int[plainText.length()];
for (int indexSelector = 0, comparisonNumber = 1; indexSelector < plainText.length(); comparisonNumber++) {
if( storedInput[indexSelector] == ' ') {
System.out.print(" <SPACE> ");
}
else {
if( ((int) storedInput[indexSelector]-64) == comparisonNumber) {
int converter = storedInput[indexSelector] - 64;
convertedInput[indexSelector] = converter;
System.out.print(convertedInput[indexSelector]);
}
else {
continue;
}
}
}
}
This code takes an input (hello), turns all letters to upper case, and then when I get the integer I subtract 64 because it returns the ASCII integer. After this A becomes 1, B becomes 2, C becomes 3 and so on....
When I try to convert hello (or any other words) it takes at least 8 seconds. Any suggestions on why?
You need to simplify your program. comparisonNumber is causing you significant problems, and you generally should avoid multiple variables in your for loop unless you really know what you are doing. Even in professional settings I would consider a , in a for loop a problem that needs to be justified.
In your case you are looping on comparisonNumber but never using it for anything but verifying you hit the right number, where you then ignore the value and do operations that are independent of it. Since you don't reset the value, it loops through all the possible values before continuing to process the next letter.
Here is a version that might be closer to what you are looking for, I just removed that variable and left everything else as is.
public static void encrypt(String plainText) {
Random random = new Random();
plainText.toUpperCase();
char[] storedInput = plainText.toCharArray();
int[] convertedInput = new int[plainText.length()];
for (int indexSelector = 0; indexSelector < plainText.length(); indexSelector++) {
if( storedInput[indexSelector] == ' ') {
System.out.print(" <SPACE> ");
} else {
int converter = storedInput[indexSelector] - 64;
convertedInput[indexSelector] = converter;
System.out.print(convertedInput[indexSelector]);
indexSelector++;
}
}

Categories