Generate Random String Containing Alpha-Numeric and Special Chars? - java

I'm interested in generating a (secure) random String with the following properties:
Atleast 1 upper case letter
Atleast 1 lower case letter
Atleast 1 digit from 0-9
Atleast one special char from chars $&#?<>~!%#
The length of string should be from 12-13 digits/chars long.
I know there is a class in Apache commons that can help generate random Strings however there is no option to include special chars.
I'm also aware of some other similar questions on SO however none of them address exactly these requirements.
I've tried the following so far:
import java.security.SecureRandom;
public final class SessionIdentifierGenerator {
private SecureRandom random = new SecureRandom();
public String nextSessionId() {
return
new BigInteger(130, random).toString(32);
}
}
But it does not contain char set from each of the 4 points.
I also tried:
static final String AB = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
static Random rnd = new Random();
String randomString( int len )
{
StringBuilder sb = new StringBuilder( len );
for(int i = 0; i < len; i++)
sb.append(AB.charAt( rnd.nextInt(AB.length())));
return sb.toString();
}
I know I can modify the String AB to include special chars but there's no way to guarantee string will contain Atleast 1 upper, 1 lower, 1 digit and 1 special char.
I'm using Java.

The easiest way in your case is to generate the random password containing any of allowed symbols, then test whether the criteria met:
private static final String symbols =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789$&#?<>~!%#";
public static String genPassword(Random r) {
while(true) {
char[] password = new char[r.nextBoolean()?12:13];
boolean hasUpper = false, hasLower = false, hasDigit = false, hasSpecial = false;
for(int i=0; i<password.length; i++) {
char ch = symbols.charAt(r.nextInt(symbols.length()));
if(Character.isUpperCase(ch))
hasUpper = true;
else if(Character.isLowerCase(ch))
hasLower = true;
else if(Character.isDigit(ch))
hasDigit = true;
else
hasSpecial = true;
password[i] = ch;
}
if(hasUpper && hasLower && hasDigit && hasSpecial) {
return new String(password);
}
}
}
According to my tests, number of required iterations rarely exceeds 5 and in more than half tests the first generated password meets the criteria. Though don't force your users to memoize such passwords! Here's how they look like:
c3h$oyuKcZZl
Si4e8F4sWjy#i
V$9WwW7zJ8ba
~9htwMwcFc!s
wBm94~AH%z%MU
p4TE36S&Y>J14
R9Bsqq#23eYk
PTfcvR5u?piZQ
CE8ot>a74PmZP
4zAco~P6Xuf3E
aiv?VDN4j9pE

Set up an array/list/whatever of characters. Pick a random lowercase letter and put it into your array. Pick a random uppercase letter and put it into your array. Pick a random digit and put it into your array. Pick a random special character and put it into your array. You have four characters in your array which partly meets your requirements.
Now pick as many more characters as you need at random from the string: "A-Za-z0-9$&#?<>~!%#" Add each selected character to your character array.
Now shuffle your character array to mess up the order of the first four characters.
Convert the shuffled array to a string.

The following works well for me. Note, that you could pass in a specific Random implementation if you didn't want to use RandomUtils.
public class RandomUtil {
public static final String ALPHABETIC_UPPERCASE_SYMBOLS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
public static final String ALPHABETIC_LOWERCASE_SYMBOLS = "abcdefghijklmnopqrstuvwxyz";
public static final String NUMERIC_SYMBOLS = "0123456789";
public static final String SPECIAL_SYMBOLS = "$&#?<>~!%#";
public static final String ALPHANUMERIC_AND_SPECIAL_SYMBOLS =
ALPHABETIC_UPPERCASE_SYMBOLS +
ALPHABETIC_LOWERCASE_SYMBOLS +
NUMERIC_SYMBOLS +
SPECIAL_SYMBOLS;
public static String generateRandomAlphanumericAndSpecialCharactersKey(int length) {
List<Character> chars = new ArrayList<>(length);
boolean hasUpper = false;
boolean hasLower = false;
boolean hasNumber = false;
boolean hasSpecial = false;
for (int i = 0; i < length; i++) {
// Make sure we have at least one upper, lower, number and special character.
// Then, fill randomly from set containing all characters.
if (!hasUpper) {
chars.add(ALPHABETIC_UPPERCASE_SYMBOLS.charAt(RandomUtils.nextInt(0, ALPHABETIC_UPPERCASE_SYMBOLS.length())));
hasUpper = true;
} else if (!hasLower) {
chars.add(ALPHABETIC_LOWERCASE_SYMBOLS.charAt(RandomUtils.nextInt(0, ALPHABETIC_LOWERCASE_SYMBOLS.length())));
hasLower = true;
} else if (!hasNumber) {
chars.add(NUMERIC_SYMBOLS.charAt(RandomUtils.nextInt(0, NUMERIC_SYMBOLS.length())));
hasNumber = true;
} else if (!hasSpecial) {
chars.add(SPECIAL_SYMBOLS.charAt(RandomUtils.nextInt(0, SPECIAL_SYMBOLS.length())));
hasSpecial = true;
} else {
chars.add(ALPHANUMERIC_AND_SPECIAL_SYMBOLS.charAt(RandomUtils.nextInt(0, ALPHANUMERIC_AND_SPECIAL_SYMBOLS.length())));
}
}
// Shuffle characters to mix up the first 4 characters
Collections.shuffle(chars);
return StringUtils.join(chars, "");
}
}

Related

Can we generate multiple random strings as per regex /^[0-9A-F]$/

Can we generate multiple random strings as per regex /^[0-9A-F]$/
I have written the below code, is there any better way to generate it, please do not use any lib, use only java API
public static void printRandomStrings(int numOfStrings){
Random random = new Random();
char[] chars = {'A','B','C','D','E','F'}; // 6 characters
for(int i=0;i<numOfStrings;i++){
String randomString = "";
for(int j=0;j<4;j++){
int choice = random.nextInt(2); // 0 -1
if(choice == 1){
randomString= randomString+generateRandomInt(random);
}else{
randomString= randomString+generateRandomChar(random,chars);
}
}
System.out.println(randomString);
}
}
public static int generateRandomInt(Random random){
return random.nextInt(10);
}
public static char generateRandomChar(Random random,char[] chars){
int charIdx = random.nextInt(6);
return chars[charIdx];
}

Alpha Numeric Random Number Sequence [5-digit or 6-digit or any digit] generation

Hi I am trying to generate a 5 digit random number which is alpha numeric in nature. I am doing both with without using Streams.
CODE
public class AlphaRandom {
private static final String ALPHA_NUMERIC_STRING = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
static final Random random = new Random();
public static void main(String args[]) {
int length = 5;
String seq = randomAlphaNumeric(length);
System.out.println("Random Number Normal : " +seq);
IntStream.range(0,1).forEach(i->System.out.println("Random Number Streams : " +generateRandomString(random, length)));
}
// Using Streams
private static String generateRandomString(Random random, int length){
return random.ints(48,122)
.filter(i-> (i<57 || i>65) && (i <90 || i>97))
.mapToObj(i -> (char) i)
.limit(length)
.collect(StringBuilder::new, StringBuilder::append, StringBuilder::append)
.toString();
}
// Normal
public static String randomAlphaNumeric(int count) {
StringBuilder builder = new StringBuilder();
while (count-- != 0) {
int character = (int)(Math.random()*ALPHA_NUMERIC_STRING.length());
builder.append(ALPHA_NUMERIC_STRING.charAt(character));
}
return builder.toString();
}
}
Sample Outputs :
Random Number Normal : VYAXC
Random Number Streams : LdBN6
Random Number Normal : 2ANTT
Random Number Streams : hfegc
Random Number Normal : JWK4Y
Random Number Streams : 8mQXK
But I am unable to generate the sequence always starting with a UpperCase only.
Can someone help me out.
I will use RandomStringUtils from the apache library to do this. The reason to do this is less code and I believe better readability of the code.
This is my code which can do the required thing
import org.apache.commons.lang3.RandomStringUtils;
public class GenerateRandomString {
public static void main(String[] args) {
int keyLength = 5; // Number of character allowed as per requirement
String randomAlphanumeric = RandomStringUtils.randomAlphanumeric(keyLength);
System.out.println("randomAlphanumeric generated is " + randomAlphanumeric);
String upperCaseRandom = randomAlphanumeric.substring(0, 1).toUpperCase() + randomAlphanumeric.substring(1);
System.out.println("upperCaseRandom generated is " + upperCaseRandom);
}
}
It would generate the following output:
randomAlphanumeric generated is m8OiR
upperCaseRandom generated is M8OiR
I am making the first character to uppercase as required by question using the substring method.
The easiest way is that before to return your string (once you have generated it), you take the first letter in order to apply toUpperCase and on the remaining chars, apply toLowerCase. Also, if in the future you will need to generate longer strings, you can use the same method without changing anything.
Summering what we'll do is:
public static String manipulate (String rand){
String c = rand.substring(0,1); // where rand is the random alphanumeric generated by your methods, we pick the first char
c = c.toUpperCase(); //we make it upperCase
String split = rand.substring(1); //we get the remaining of the string starting from position 1
split = split.toLowerCase(); //let's apply lowercase on the remaining
String result = c+split; //join again
return result;
}
Full Code:
package test;
import java.util.Random;
import java.util.stream.IntStream;
public class AlphaRandom {
private static final String ALPHA_NUMERIC_STRING = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
static final Random random = new Random();
public static void main(String args[]) {
int length = 5;
String seq = randomAlphaNumeric(length);
System.out.println("Random Number Normal : " +seq);
IntStream.range(0,1).forEach(i->System.out.println("Random Number Streams : " +generateRandomString(random, length)));
}
public static String manipulate (String rand){
String c = rand.substring(0,1); // where rand is the random alphanumeric generated by your methods, we pick the first char
c = c.toUpperCase(); //we make it upperCase
String split = rand.substring(1); //we get the remaining of the string starting from position 1
split = split.toLowerCase(); //let's apply lowercase on the remaining
String result = c+split; //join the again
return result;
}
// Using Streams
private static String generateRandomString(Random random, int length){
String rand = random.ints(48,122)
.filter(i-> (i<57 || i>65) && (i <90 || i>97))
.mapToObj(i -> (char) i)
.limit(length)
.collect(StringBuilder::new, StringBuilder::append, StringBuilder::append)
.toString();
return manipulate(rand);
}
// Normal
public static String randomAlphaNumeric(int count) {
StringBuilder builder = new StringBuilder();
while (count-- != 0) {
int character = (int)(Math.random()*ALPHA_NUMERIC_STRING.length());
builder.append(ALPHA_NUMERIC_STRING.charAt(character));
}
return manipulate(builder.toString());
}
}
Output:
Random Number Normal : Mwwsz
Random Number Streams : Q1fqk

Generate Random String in java [duplicate]

This question already has answers here:
How to generate a random alpha-numeric string
(46 answers)
Closed 6 years ago.
I'm trying to generate a string between capital A-Z in java using Secure Random. Currently I'm able to generate an alphanumeric string with special characters but I want a string with only upper case alphabets.
public String createRandomCode(int codeLength, String id){
char[] chars = id.toCharArray();
StringBuilder sb = new StringBuilder();
Random random = new SecureRandom();
for (int i = 0; i < codeLength; i++) {
char c = chars[random.nextInt(chars.length)];
sb.append(c);
}
String output = sb.toString();
System.out.println(output);
return output ;
}
The input parameters are length of the output string & id whhich is alphanumeric string.Can't understand what modifications to make to the above code to generate only upper case alphabet string. Please help..
Your method randomly selects characters out of the id argument. If you want those to only be uppercase letters, then pass a string with those characters:
String randomCode = createRandomCode(length, "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
EDIT If you want to avoid duplicates, you can't just select characters at random. You'll want to shuffle them and pick out the first n characters:
public String createRandomCode(int codeLength, String id) {
List<Character> temp = id.chars()
.mapToObj(i -> (char)i)
.collect(Collectors.toList());
Collections.shuffle(temp, new SecureRandom());
return temp.stream()
.map(Object::toString)
.limit(codeLength)
.collect(Collectors.joining());
}
EDIT 2 Just for fun, here's another way to implement the original random code generator (allowing duplicates):
public static String createRandomCode(int codeLength, String id) {
return new SecureRandom()
.ints(codeLength, 0, id.length())
.mapToObj(id::charAt)
.map(Object::toString)
.collect(Collectors.joining());
}
Here is generator that I wrote and use:
public class RandomGenerator {
private static final String characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
public static String generateRandom(int length) {
Random random = new SecureRandom();
if (length <= 0) {
throw new IllegalArgumentException("String length must be a positive integer");
}
StringBuilder sb = new StringBuilder(length);
for (int i = 0; i < length; i++) {
sb.append(characters.charAt(random.nextInt(characters.length())));
}
return sb.toString();
}
}
in numChars string you can put any characters you want to be included. int length parameter is the length of generated random string.
Here is an example method that uses the int range for characters A to Z (also this method avoids duplicate characters in the String) :
public String createRandomCode(final int codeLength) {
int min = 65;// A
int max = 90;// Z
StringBuilder sb = new StringBuilder();
Random random = new SecureRandom();
for (int i = 0; i < codeLength; i++) {
Character c;
do {
c = (char) (random.nextInt((max - min) + 1) + min);
} while (sb.indexOf(c.toString()) > -1);
sb.append(c);
}
String output = sb.toString();
System.out.println(output);
return output;
}
The range part comes from this topic : Generating random integers in a specific range

Code verifcation and optimization - Two String common substring

I was solving Two String problem. I have written below code.
It passed 4 test cases but for two test cases it showed timeout. Kindly let me know how can I optimize it to avoid timeouts? Also any links which explains and shows examples of such optimization is welcome.
public class TwoStrings
{
private static final String YES = "YES";
private static final String NO = "NO";
public static void main(String[] args)
{
Scanner in = new Scanner(System.in);
int testCases = Integer.parseInt(in.nextLine());
String input1[] = new String[testCases];
String input2[] = new String[testCases];
for (int i = 0; i < testCases; i++)
{
input1[i] = in.nextLine();
input2[i] = in.nextLine();
}
in.close();
for (int i = 0; i < testCases; i++)
{
displayResult(input1[i], input2[i]);
}
}
private static void displayResult(String string1, String string2)
{
// choosing smaller String for iterating through it.
String smallerString = string1.length() <= string2.length() ? string1
: string2;
String biggerString = string1 == smallerString ? string2 : string1;
boolean constains = false;
// Concept - Even if single letter is common, substring exists.
// So checking just one string.
for (int i = 0; i < smallerString.length(); i++)
{
if (biggerString.contains(String.valueOf(smallerString.charAt(i))))
{
constains = true;
break;
}
}
if (constains)
System.out.println(YES);
else
System.out.println(NO);
}
}
What you are currently doing is O(n^2) because you loop through the small string and the search for that character in the longer string is a linear search because it is not sorted (all letters in alphabetical order).
Below is a O(n) solution. The concept is to have a size 26 boolean array (one for each letter), and make an index true if a letter is in the small (could actually be small or long string, doesn't matter) string. Creating the array from the small string is O(n), and checking the letters in the long string is O(n), yielding a grand total of O(n + n), which reduces to O(n).
private static void displayResult(String string1, String string2)
{
boolean[] contains = new boolean[26];
boolean noSubstring = true;
// populate the contains array
for (char c : string1.toCharArray())
{
int value = (int)c - (int)'a'; // make the char 0-25
contains[value] = true;
}
for (char c : string2.toCharArray())
{
int value = (int)c - (int)'a'; // make the char 0-25
if (contains[value])
{
noSubstring = false;
break;
}
}
if (noSubstring) System.out.println("NO");
else System.out.println("YES");
}

4 digits numbers in an array as String

I need a String array with the following attributes:
4 digits numbers
No repeating digits ("1214" is invalid)
No 0's
Is there an easier way to do this than manually type it? Like:
String[] s = {"1234","1235",1236",1237",1238",1239","1243","1245"};
Sorry for my English!
The following code will generate an array with your specifications.
public class Test {
public static void main(String[] args) {
List<String> result = new ArrayList<>();
Set<Character> set = new HashSet<>();
for (int i = 1234; i <= 9876; i++) {
set.clear();
String iAsString = Integer.toString(i);
char[] chars = iAsString.toCharArray();
boolean valid = true;
for (char c : chars) {
if (c == '0' || !set.add(c)) {
valid = false;
break;
}
}
if (valid) {
result.add(iAsString);
}
}
String[] yourStringArray = result.toArray(new String[result.size()]);
System.out.println(Arrays.toString(yourStringArray));
}
}
****edit****
Just saw that it is in Java. So use this function: String.valueOf(number) to convert integer to string if none of the digits are repeats in the loop.
Not sure what language you are doing but I am assuming no repeats not replies.
So what you can do is have a loop from 0 to 9999 and then run through all the numbers while checking if each digit has repeats if so discard number (do not store it into array).
You can convert integers to strings in many languages in their function so you can do that then store it into array.
Good luck.
Hope this helped (fastest solution from my head...there could be more efficient ones)
Try this method for creating Random number with your structure :
ArrayList<Integer> rawNumbers = new ArrayList<Integer>(Arrays.asList(1,2,3,4,5,6,7,8,9));
public String createRandomNumberSring()
{
String result = "";
ArrayList<Integer> numbers = new ArrayList<Integer>();
numbers.addAll(rawNumbers);
for(int i = 0; i < 4; i++)
{
int index = (int)(Math.random() * (numbers.size() + 1));
result += numbers.get(index).toString();
numbers.remove(index);
}
return result;
}

Categories