How to create an array of random security codes in Java? [duplicate] - java

This question already has answers here:
Using Regex to generate Strings rather than match them
(12 answers)
Closed 9 months ago.
This post was edited and submitted for review 9 months ago and failed to reopen the post:
Original close reason(s) were not resolved
I am trying to write a program that would ask the user how many security codes he wants to generate, then it would output as many codes as he requested in an array.
The security code should be 7 characters long and have the following format: NNNNLLL, where N is a random number and L is a random upper case letter.
The method should create security codes with the above format by randomly selecting the characters, i.e. numbers and letters.
I am expecting the program to output something like this if a user selects to generate 4 codes:
“2394QAB”
“2821TSZ”
“7173AAY”
“2236WQA”
I can only use the methods for this code learned in my course and I cannot use other libraries like regex, that is why I am trying it like this.
This is the code I have done so far:
import java.util.Random;
public class ItemChecker{
private StringBuffer strBuff;
private String[] codes;
private String CodeLetters, CodeNumbers;
private int[] RandomNums;
public ItemChecker(){
strBuff=new StringBuffer();
}
public String[] getCodes(int[] amount){
codes=new String[amount.length];
for(int i=0;i<amount.length;i++)
{
CodeLetters="";
strBuff=new StringBuffer();
for(int j=0;j<4;j++)
{
Random RandomNumber=new Random();
int randomIndex=RandomNumber.nextInt(RandomNums.length);
CodeNumbers.append(RandomNumber[randomIndex]);
}
for(int j=0;j<3;j++)
{
Random RandomLetter=new Random();
char c =(char)(RandomLetter.nextInt(26)+'a');
CodeLetters+=c;
}
codes[i]=CodeNumbers+CodeLetters;
}
}
}
My intention is to create 4 random digits and 3 random letters and add them together in a string to make the code. However, the code doesn't generate the random codes and I have no clue how to proceed from here.

Within your getCodes method there are a couple of mistakes. A StringBuiler would be more appropriate for this task, instead of using a StringBuffer or chaining strings with the + operator. As a matter of fact, each time you're performing a concatenation with the + operator you're creating a new string in memory, rather than working on a same instance, this is not that efficient. Also, when you're adding an offset to the random value representing an upper case letter, you're adding the lower case 'a', instead of the upper case 'A'.
In your program, you could define a static method to offer the code generation service as a general utility and then invoke it within your getCodes method.
In the utility method, you could declare a Random object to get random int values. Then, with a first for loop, you could generate random values between 0 included and 10 excluded, and append them to a StringBuilder object. The String class represents immutable objects, so you need to use a StringBuilder to build one. As said above, chaining strings with the + operator will create new instances at each concatenation, you're not working on the same object.
Then, with a second for loop you could generate random values from 0 to 27 excluded, add to every value the offset 65, representing the upper case 'A' letter (lower case 'a' has value 97), and then cast this int value to a char to get its character representation. Finally, append the char to your StringBuilder instance.
Here is an implementation:
public class Main {
public static void main(String[] args) {
System.out.println(getSecurityCode());
}
public String[] getCodes(int[] amount) {
String[] codes = new String[amount.length];
for (int i = 0; i < codes.length; i++) {
codes[i] = getSecurityCode();
}
return codes;
}
public static String getSecurityCode() {
Random rand = new Random();
StringBuilder strBuilder = new StringBuilder();
//Appending 4 random digits
for (int i = 0; i < 4; i++) {
//nextInt(10) returns a value between 0 (included) and 10 (excluded)
strBuilder.append(rand.nextInt(10));
}
//Appending 3 random upper case letters
for (int i = 0; i < 3; i++) {
//rand.nextInt(27) returns a random value between 0 and 26 included to represent an alphabet letter.
//This value is added with the offset 65 which represents the upper case A letter.
//Finally, this value is cast as a char or else it would append its int value
strBuilder.append((char)(65 + rand.nextInt(27)));
}
return strBuilder.toString();
}
}

To simplify your code that generate the password you could use RandomStringUtils from org.apache.commons.lang3.RandomStringUtils like described in this great tutorial https://www.baeldung.com/java-random-string.
You just have to generate 2 strings :
One with 4 digits
One with 3 letters to uppercase
And concat both.
Here's How
public static String getSecurityCode() {
//generate 4 numbers only
String generatedNumbers = RandomStringUtils.random(4, false, true);
//generate 3 letters only
String generatedLetters = RandomStringUtils.random(3, true, false).toUpperCase();
return generatedNumbers + generatedLetters;
}
Or with StringBuilder
public static String getSecurityCode2() {
StringBuilder stb=new StringBuilder(7);
//generate 4 numbers only
stb.append(RandomStringUtils.random(4, false, true));
//generate 3 letters only
stb.append( RandomStringUtils.random(3, true, false).toUpperCase());
return stb.toString();
}

Another way of doing this is to utilize StringBuilder's appendCodePoint method for this:
int number= random.nextInt(10000); //generate any number between 0 to 9999
StringBuilder builder=new StringBuilder();
for(int i=0;i<3;i++) {
builder.appendCodePoint(65+random.nextInt(26));
}
String result=number+builder.toString();
System.out.println(result);

Related

How to delete characters at x?

How to delete the characters at x and keep the rest? The output should be "12345678" Deleting every '9' in the position that x is on. X is i*(i+1)/2 so that the number is added to the next number. So every number at 0,1,3,6,10,15,21,28,etc.
public class removeMysteryI {
public static String removeMysteryI(String str) {
String newString = "";
int x=0;
for(int i=0;i<str.length();i++){
int y = (i*(i+1)/2)+1;
if(y<=str.length()){
x=i*(i+1)/2;
newString=str.substring(0, x) + str.substring(x + 1);
}
}
return newString;
}
public static void main(String[] args) {
String str = "9919239456978";
System.out.println(removeMysteryI(str));
}
}
OK, so there are a couple of mistakes in your code. One is easy to fix. The others not so easy.
The easy one first:
newString=str.substring(0, x) + str.substring(x + 1);
OK so that is creating a string with the character at position x removed. The problem is what it is operating on. The str variable is the input parameter. So at the end of the day newString will still only be str with one character removed.
The above actually needs to be operating on the string from the previous loop iterations ... if you are going to remove more than one character.
The next problem arises when you try to solve the first one. When you remove a character from a string, all characters after the removal point are renumbered; e.g. after removing the character at 5, the character at 6 becomes the character at 5, the character at 7 becomes the character at 6, and so on.
So if you are going to remove characters by "snipping" the string, you need to make sure that the indexes for the positions for the "snips" are adjusted for the number of characters you have already removed.
That can be done ... but you need to think about it.
The final problem is efficiency. Each time your current code removes a single character (as above), it is actually copying all remaining characters to a new string. For small strings, that's OK. For really large strings, the repeated copying could have a serious performance impact1.
The solution to this is to use a different approach to removing the characters. Instead of snipping out the characters you want to discard, copy the characters that you want to keep. The StringBuilder class is one way of doing this2. If you are not permitted to use that, then you could do it with an array of char, and an index variable to keep track of your "append" position in the array. Finally, there is a String constructor that can create a String from the relevant part of the char[].
I'll leave it to you to work out the details.
1 - Efficiency could be viewed as beyond the scope of this exercise.
2 - #Horse's answer uses a StringBuilder but in a different way to what I am suggesting. This will also suffer from the repeated copying problem because each deleteCharAt call will copy all characters after the deletion point.
Follow the steps below:
Initialize with builderIndexToDelete = 0
Initialize with counter = 1
Repeat the following till the index is valid:
delete character at builderIndexToDelete
update builderIndexToDelete to counter - 1 (-1 as a character is deleted in every iteration)
increment the counter
public static String deleteNaturalSumIndexes(String str) {
StringBuilder builder = new StringBuilder(str);
int counter = 1;
int builderIndexToDelete = 0;
while (builderIndexToDelete < builder.length()) {
builder.deleteCharAt(builderIndexToDelete);
builderIndexToDelete += (counter - 1);
counter++;
}
return builder.toString();
}
public static void main(String[] args) {
String str = "9919239456978";
System.out.println(deleteNaturalSumIndexes(str));
}
Thank you #dreamcrash and #StephenC
Using #StephenC suggestion to improve performance
public static String deleteNaturalSumIndexes(String str) {
StringBuilder builder = new StringBuilder();
int nextNum = 1;
int indexToDelete = 0;
while (indexToDelete < str.length()) {
// check whether this is a valid range to continue
// handles 0,1 specifically
if (indexToDelete + 1 < indexToDelete + nextNum) {
// min is used to limit the index of last iteration
builder.append(str, indexToDelete + 1, Math.min(indexToDelete + nextNum, str.length()));
}
indexToDelete += nextNum;
nextNum++;
}
return builder.toString();
}
public static void main(String[] args) {
System.out.println(deleteNaturalSumIndexes(""));
System.out.println(deleteNaturalSumIndexes("a"));
System.out.println(deleteNaturalSumIndexes("ab"));
System.out.println(deleteNaturalSumIndexes("abc"));
System.out.println(deleteNaturalSumIndexes("99192394569"));
System.out.println(deleteNaturalSumIndexes("9919239456978"));
}

Java pass generator with special requirements

I just need a password generator with special requirements.
I did this code. It works very well but how to take from this String-only 2 special character;-only 2 digits;-only 3 characters in lowercase;-only 3 characters in uppercase.
private static void passGenerator(){
int length = 8;
String symbol = "-/.^&*_!#%=+>)";
String cap_letter = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
String small_letter = "abcdefghijklmnopqrstuvwxyz";
String numbers = "0123456789";
String finalString = cap_letter + small_letter +
numbers + symbol;
Random random = new Random();
char[] password = new char[length];
for (int i = 0; i < length; i++)
{
password[i] = finalString.charAt(random.nextInt(finalString.length()));
}
System.out.println(password);
}
You could try this library by apache. There are some useful methods for split string to array by characters with different cases, by different characters at all (a3 will be a, 3)
I would first generate the password in a specific order and store it in a temporary variable, say like this:
{ special1, special2, digit1, digit2, lower1, lower2, lower3, upper1, upper2, upper3}
This would likely need to be hard coded.
Next, I would create a new password variable, and one by one choose a character and add it to the new variable. Do this by randomly generating a number [0, temp.length). Then, copy the char at that index to the lowest unfilled spot in the new password, remove it from the temp, and copy all the remaining chars to a new temp array one element smaller. Repeat until the temp array size is zero.

How to populate an array (like hangman) based on a guess

What I am trying to do is take a hidden String and then display it letter by letter in a random sequence every time the user presses the hint button. Currently, every time the hint button is pressed the entire solution displays once per character of the solution.
I am trying to make it so that when the hint button is pressed a random character from the string solution appears in the correct location. I am unsure about how to compare the location of the generated character to the string location.
public String letterGenerator(int count, String word) {
//String word is taken from another function and it is based on the current displayed card and associated answer
StringBuilder string = new StringBuilder();
Random rng = new Random();
char[] letters = word.toCharArray();
char[] answers = new char[letters.length];
int selected = rng.nextInt(letters.length);
for (int i = 0; i < word.length(); i++) {
if (i == selected) {
letters[i] = answers[i];
}
string.append(letters);
}
return string.toString();
}
For example if the answer is "a wallet" this code outputs the solution as "a walleta walleta walleta walleta walleta walleta walleta walleta" (It displays the output 8 times because it prints the solution once per character including blank spaces)
What it should be doing for each press of the hint button would be to display each character in a random order like so:
Press 1: "_ _ _ l_ _ _"
Press 2: "a _ _ l_ _ _"
Press 3: "a _ _ l _e _", and so on until the entire word appears on screen
Any help is appreciated!
Well, you append(letters) to your output for each iteration of your loop, and letters is an array of all your letters, not just one of them. So of course you end up with that output that you got.
But I think you can design this in a more elegant, and more object-oriented way. Instead of two character arrays for the answer and what is displayed, maybe make just one array of 'Letters'. This means you create a custom class Letter, which could hold the information whether it is 'solved' or not. Like so:
public class Letter{
char character;
boolean solved;
// ... Constructor, Getters, Setters
}
Then, you can just pass your array of letters to a method that selects a random letter that is not solved yet, and simply switch its solved property to true. Your code for displaying the thing to your user would then be something like this:
for(Letter letter : letterArray){
System.out.print(letter.isSolved() ? letter.getCharacter() : "_");
}
If I've understood correctly, then here's a few things to change;
1) You want to remember the last revealed hint, but you've stored it in a local variable.
You'll want a way to store the revealed letters. How you do that depend on how the rest of your class is setup, but either passing it back as part of the method return or setting a global variable should do
2) Since you are remembering the previous hints, you'll want to make sure that 'selected' has not been revealed before. Perhaps store what letter positions have been revealed before and compare against them.
3) I would put the internal of the loop more as
for (int i = 0; i < word.length(); i++) {
if(i == selected){
string.append(letters[i]);
}else{
string.append("_");
}
}
I hope this helps
Edit:
I've changed the for loop, now it should work as you wanted. Sorry I should have been more careful to start with.
As for storing the previously revealed letters, if you are using a Singleton class then it would be acceptable to store this values in another list. My suggestion would be to keep an ArrayList of revealed values, then do something like;
List<Integer> revealed = new ArrayList<>();
Random rng = new Random();
public int getNextSelected(int length){
int selected = rng.nextInt(length);
if(revealed.contains(selected)){
return getNextSelected(length);
}
return selected;
}
public String letterGenerator(int count, String word) {
...
int selected = getNextSelected(letters.length);
for (int i = 0; i < word.length(); i++) {
if (i == selected){
string.append(letters[i]);
} else if (revealed.contains(i)) {
string.append(letters[i]);
} else{
string.append("_");
}
}
revealed.add(selected);
return string.toString();
}
This should do what you need. There's plenty of ways to clean up the code, the suggestion by user3237736 is quite nice as it follows the 'tell don't ask' principle, but the design decisions of the class is up to you
public class SOEN_student {
public static void letterGenerator(String word) {
//String word is taken from another function and
//it is based on the current displayed card and associated answer
StringBuilder string;
Random rng = new Random();
char[] letters = word.toCharArray();
char[] answers = new char[letters.length];
boolean[] visited=new boolean[letters.length];
int selected;
for (int i = 0; i < word.length(); i++) {
do{
selected=rng.nextInt(letters.length);
}while(visited[selected]);
string=new StringBuilder();
for(int j=0;j<word.length();j++){
if(visited[j] | j==selected){
visited[selected]=true;
string.append(letters[j]);
}else{
string.append("_");
}
}
System.out.print(string.toString()+" ");
}
}
public static void main(String... args){
letterGenerator("a wallet");
}
}

Print random characters from string

I want to print three random characters, chosen from a given string. But I have no idea how to do random things like this!
See the "Bonus Opportunity" in this question.
Here is my code, split into 2 parts with the extra credit part being on the right side.
It depends on what "random" means in this case.
Weighted probability
If repeating characters should be given a higher chance of being chosen, simply concatenate the first name, middle name, and last name into one string:
String s = first + middle + last;
Then generate a random number between 0 and the length of the string:
Random r = new Random();
int R = r.nextInt(s.length());
Use this random number to index the particular character:
output_character = s.charAt(R);
Repeat as many times as desired.
Equal probability
If each of the characters are to have the same probability as the others, you will need to push unique characters into a list and repeat the same procedure as described above.
It is a little dishonest, academically, to ask for the solution to a homework question. It would be a bit less problematic if you'd do a little thinking on your own.
As #Zar mentioned in the comment above, asking something like "How do I get a random character in Java" would be simpler, and would give you what you need to answer the question without asking someone else to hand it to you.
import java.util.Random;
public class RandomAddingTest {
public static void main(String[] args){
System.out.println(returnNewPass("abcabc"));
//display something like:[abcabcwMS][abcabcCln][abcabc?p=]...so on
}
public static String returnNewPass(String oldPass){
StringBuilder sb = new StringBuilder(oldPass);
Random ran = new Random();
char c ;
for (int i = 0; i<3; i++){
c = (char)(ran.nextInt(93)+33);//ran will generate A~Z,a~z,0~9,##$%^&*...so on
sb.append(c);
}
return sb.toString();
}
}

How do I generate all possible numbers from this regular expression? [duplicate]

This question already has answers here:
Using Regex to generate Strings rather than match them
(12 answers)
Closed 7 years ago.
I want to get a list of all possible values for a regular expression.
Input :
2W
9WW
7W0W3
where W can be any digit from 0 to 9. i.e. W = [0-9]
Output:
20,21,22,....29
900,901,...910,911,...999
70003,70013,70023,...71003,72003,...79093
What I did :
I'm using Java and decided to create an ArrayList of Integers.
I created a method ArrayList<Integer> getNumbers(String regex).
ArrayList<Integer> getNumbers(String regex){
ArrayList<Integer> fullList = new ArrayList<Integer>();
char[] cArray = regex.toCharArray(); //converted the string into a character array.
for(int i=1;i<cArray.length;i++) {
if(cArray[i] == 'W') {
for(int j=0;j<10;j++) {
//I'm not sure what goes here
fullList.add(the number with 'w' at this index replaced by 'j');
}
}
}
return fullList;
}
Is there any better way or library functions available to generate all such numbers?
How can I achieve this?
This is not quite a regex-based problem, but from an algorithmic perspective you can do the followings:
Count the number of W's in your string.
Based on the number of W's, create the product of range(0,9), for example if you have 2 W you need to create the products of two [0...9] lists that will be something like 0,0-0,1-0,2-...-9,9.
Loop over the combinations and replace them with a simple string formatting. For instance when you are iterating over a triple combination suppose with 3 variables i,j,k you want want to replace them in a string like 7W0W3W, you can do "7%d0%dW%d"%(i,j,k).
And if you are looking for a general regex to wrap all the cases you can use a regex like (w) (w in a capture group) then you need to first access to position of the match groups and replace them with combination items (i,j,k,..).
It's better to call the input string as "pattern", not "regular expression". Also it's probably better to create a "virtual" list which generates the strings on demand. Here's the sample implementation:
public static List<String> getNumbers(String pattern) {
final char[] chars = pattern.toCharArray();
int size = 1;
for(char ch : chars)
if(ch == 'W') {
if(size == 1_000_000_000)
throw new IllegalArgumentException("Too many 'W' to fit the list");
size*=10;
}
final int finalSize = size;
return new AbstractList<String>() {
#Override
public String get(int index) {
char[] res = chars.clone();
for(int i=res.length-1; i>=0; i--) {
if(res[i] == 'W') {
res[i] = (char) ('0'+(index % 10));
index/=10;
}
}
return new String(res);
}
#Override
public int size() {
return finalSize;
}
};
}
First we count the number of 'W' chars and calculate the target list size accordingly. Then we return an implementation of AbstractList which for given list index replaces the 'W' symbols with the remainders of index division by 10. This list does not take the memory, it generates the String only when you request it. If you want to get the hard-copy of such list, you can use new ArrayList<>(getNumbers(pattern)).

Categories

Resources