I want to write some automated tests for web app authentication. The login password is case-sensitive and always contains at least one alphabetic character.
I want to write a test where I randomly change the case of one or more alphabetic characters.
Let's say the password string is "123te123st!".
Now I want to change this string to one which contains at least one uppercase letter. I'm trying to make sure that the login is still case-insensitive and any variation in case will fail to match the password.
Does anybody know a elegant way to do it? I searched already (including Apache Commons) but couldn't find a helper method.
You can look at the randomAlphaNumeric from the RandomStringUtils, although it would seem that you are not guaranteed for it to have an upper case. To go around this, you could get the first lowercase letter and use the .toUpper() method to get it to upper case.
Alternatively, you could generate random numbers between 0 and 9 and 65 and 90 and 97 and 122. The first set should get you random numbers, you could then cast the second number to a character to get your upper case letter(s) and do the same on the last number to get your lower case ones.
That being said, when testing one usually goes for data which is predetermined rather than generating data on the fly, since that would make it easier to debug. Having a simple pool of passwords might also be easier to implement and would also allow you to better test edge cases.
class Case
{
public static void main(String ar[])
{
String s = "upperCase",split[];
split = s.split("");
int len = s.length(),i=0;
while(i!=len)
{
if(split[i].toUpperCase() == split[i])
{
System.out.println("Password Contains One UpperCase Latter");
break;
}
i++;
}
}
}
By using this code u can easily check whether string contain uppercase or not.
if output prints "Password Contains One Uppercase Latter" this message then string contain at least on uppercase.
In this case output would like:
You can use this class to generate random passwords with a constraint on uppercase letters.
import java.util.Random;
public class RandomPasswordGenerator {
private static final String ALPHA_CAPS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
private static final String ALPHA = "abcdefghijklmnopqrstuvwxyz";
private static final String NUM = "0123456789";
private static final String SPL_CHARS = "!##$%^&*_=+-/";
public static char[] generatePswd(int minLen, int maxLen, int noOfCAPSAlpha,
int noOfDigits, int noOfSplChars) {
if(minLen > maxLen)
throw new IllegalArgumentException("Min. Length > Max. Length!");
if( (noOfCAPSAlpha + noOfDigits + noOfSplChars) > minLen )
throw new IllegalArgumentException
("Min. Length should be atleast sum of (CAPS, DIGITS, SPL CHARS) Length!");
Random rnd = new Random();
int len = rnd.nextInt(maxLen - minLen + 1) + minLen;
char[] pswd = new char[len];
int index = 0;
for (int i = 0; i < noOfCAPSAlpha; i++) {
index = getNextIndex(rnd, len, pswd);
pswd[index] = ALPHA_CAPS.charAt(rnd.nextInt(ALPHA_CAPS.length()));
}
for (int i = 0; i < noOfDigits; i++) {
index = getNextIndex(rnd, len, pswd);
pswd[index] = NUM.charAt(rnd.nextInt(NUM.length()));
}
for (int i = 0; i < noOfSplChars; i++) {
index = getNextIndex(rnd, len, pswd);
pswd[index] = SPL_CHARS.charAt(rnd.nextInt(SPL_CHARS.length()));
}
for(int i = 0; i < len; i++) {
if(pswd[i] == 0) {
pswd[i] = ALPHA.charAt(rnd.nextInt(ALPHA.length()));
}
}
return pswd;
}
private static int getNextIndex(Random rnd, int len, char[] pswd) {
int index = rnd.nextInt(len);
while(pswd[index = rnd.nextInt(len)] != 0);
return index;
}
}
You can try like this:
public class Test{
public static void main(String[] args){
String s = "1a23test12hjsd2"; // Take it as a password
char[] c= s.toCharArray(); //Convert string in chararray
boolean flag= false;
StringBuilder s1= new StringBuilder();
for(int d:c){
if(d>=97 && d<=122 && !flag){ //Converting lowercase to upper case
d=d-32;
flag=true;
}
s1.append((char)d);
}
System.out.println(s1);
}
}
To generate all capitalized variants of a string, it makes sense to scan the string and store the position of each letter in a list. This will let you iterate over the letters while skipping the non-letter characters.
For example, for the string "_a_b_c_", you want to store the positions [1, 3, 5].
Next, make a boolean array of the same length as the list of letter positions. This will represent the positions of letters that have had their case inverted.
To generate the next capitalized variant, pretend that the boolean array represents a binary number in reverse. Add 1 to that boolean number, which means scanning the array from the beginning, flipping each true to false until you reach a false, which you flip to true. As you flip each bit, invert the case of the corresponding character in the string.
Thus, we get the following 23 - 1 = 7 variants of "_a_b_c_":
binary number reversed capitalized variant
001 100 _A_b_c_
010 010 _a_B_c_
011 110 _A_B_c_
100 001 _a_b_C_
101 101 _A_b_C_
110 011 _a_B_C_
111 111 _A_B_C_
Here is a complete Java implementation.
import java.util.*;
import java.io.*;
public class VaryCaps {
int wordLength,
numLetters;
Integer letterPositions[];
boolean inverted[];
StringBuffer buffer;
public VaryCaps(String word) {
wordLength = word.length();
List<Integer> positionList = new ArrayList<Integer>();
for (int i = 0; i < wordLength; ++i) {
if (Character.isLetter(word.charAt(i))) {
positionList.add(i);
}
}
numLetters = positionList.size();
letterPositions = positionList.toArray(new Integer[numLetters]);
inverted = new boolean[numLetters];
buffer = new StringBuffer(word);
}
private void invert(int index) {
int pos = letterPositions[index];
char ch = buffer.charAt(pos);
if (Character.isUpperCase(ch)) {
ch = Character.toLowerCase(ch);
} else {
ch = Character.toUpperCase(ch);
}
buffer.setCharAt(pos, ch);
inverted[index] = !inverted[index];
}
public String next() {
int index = 0;
while (index < numLetters && inverted[index]) {
invert(index++);
}
if (index == numLetters) {
return null;
}
invert(index);
return buffer.toString();
}
public static void main(String[] args) {
VaryCaps rc = new VaryCaps("_a_b_c_");
String s;
while ((s = rc.next()) != null) {
System.out.println(s);
}
}
}
Related
I am trying to sort the digits of an Integer in descending order in JAVA but I am not allowed to use any array.
This was given to me as an assignment in class and below is a code that I tried but failed.
import java.util.Scanner;
class descend
{
public static void main(String args[])
{
int a=0,loc=0,parse=0,temp=0,big=0;
Scanner scan = new Scanner(System.in);
System.out.print("Enter a number");
a=scan.nextInt();
String s=Integer.toString(a);
int l=s.length();
for(int i=0;i<l;i++)
{
big=(int)(s.charAt(i));
loc=i;
for(int j=i+1;j<l;j++)
{
parse=(int)(s.charAt(j));
if(parse>big)
{
big = parse;
loc=j;
}
}
temp=parse;
s.charAt(i)=s.charAt(loc);
s.charAt(loc)=temp
}
System.out.print(s);
}
}
Here I get a syntax error at s.charAt(i)=s.charAt(loc); and s.charAt(loc)=temp; that a variable is required but a value is given.
Please help me out with this and I shall always be grateful to you.
Maybe the teacher want to test your knowledge about the new stream API. Or maybe he wants you to test your knowledge about Collections.sort() and LinkedList (which does not contain an internal array).
1.) Here is a solution with stream API:
int number = 52214;
String.valueOf(number).chars()
.sorted()
.map(Character::getNumericValue).forEach(System.out::print);
This will print out:
12245
2.) Here is a solution with collections:
List<Integer> list = new LinkedList<Integer>();
StringCharacterIterator iterator = new StringCharacterIterator(String.valueOf(number));
for (char c = iterator.first(); c != CharacterIterator.DONE; c = iterator.next())
{
list.add(Character.getNumericValue(c));
}
Collections.sort(list);
System.out.println("list=" + list);
This will print out:
list=[1, 2, 2, 4, 5]
String cannot be changed, only replaced, hence a = b; f(b); will never change a.
With 10 digits only, you could iterate, step through, from 0 upto 9 to have the sorting:
int number = ... // or String number
if (number == 0) { // or < 10
System.out.println(number);
} else {
for (int digit = 0; digit <= 9; ++digit) {
// While being able to remove the current digit:
for (;;) {
int scrapedNumber = numberWithoutDigitOnce(number, digit);
if (scrapedNumber == number) {
break;
}
number = scrapedNumber;
System.out.print(digit);
}
}
System.out.println();
}
int numberWithoutDigitOnce(int number, int digit) {
if (number % 10 == digit) {
return number / 10;
}
int n = numberWithoutDigitOnce(number/10, digit)*10 + (number % 10);
}
Zero is a special case.
A recursive solution, you find the highest digit in the String, add it to your output String, and remove it from your input String.
Repeat until your input String is empty.
Removing the character at a given index in a String can be achieve by concatenating the characters before the index and the ones after the index. (Or with a StringBuilder but I agree with the comments on the OP that it would be cheating to use a StringBuilder)
private static String sort(String digitsLeftToSort, String sortedString) {
if(digitsLeftToSort.length() == 0) { // no more character to sort
return sortedString;
} else {
// find the index of the highest digit
int index = findIndexOfHighestDigit(digitsLeftToSort);
// add the character at that index to your output String
sortedString += digitsLeftToSort.charAt(index);
// Remove it from your input String
digitsLeftToSort = digitsLeftToSort.substring(0, index) + digitsLeftToSort.substring(index+1);
// Recursive call with your new Strings
return sort(digitsLeftToSort, sortedString);
}
}
// This finds the index of the highest digit in the given String
private static int findIndexOfHighestDigit(String s) {
int highestDigitValue = -1;
int highestDigitIndex = -1;
int integerValue;
for(int i = 0; i< s.length(); i++) {
integerValue = Character.getNumericValue(s.charAt(i));
if(integerValue > highestDigitValue) {
highestDigitValue = integerValue;
highestDigitIndex = i;
}
}
return highestDigitIndex;
}
Then
String sortedString = sort("462375623478142", "");
System.out.println(sortedString);
Outputs
877665444332221
Sorry, But after applying so much effort, I figured it out.
int n=54321;char ch;
String s=Integer.toString(n);
int l= s.length();
for(int i=48;i<=57;i++) //ascii values from 0 - 9
{
for(int j=0;j<l;j++)
{
ch=s.charAt(j);
if(ch==(char)i) // checking if a digit equals a number
{
System.out.print(ch);
}
}
}
It sorts the digits in ascending order. To sort in descending order we should use
for(int i=57;i>=48;i--)
Given 3 unique letters: can you print the six possible non repeating combinations of the letters, using a recursive function. 'cat' should output: cat, act, atc, tac, tca and cta. Here's my program, I'm having trouble finding the recursive algorithm. Here's my attempt:
static void findWords(StringBuilder string, int start, int stride) {
//1. iterate through all possible combinations of the chars recursively
System.out.println(string);
if (stride < string.length() && start < string.length())
{
char temp = string.charAt(stride);
string.setCharAt(stride, string.charAt(start));
string.setCharAt(start, temp);
findWords(string, start, stride + 1);
findWords(string, start + 1, stride + 1 );
}
}
public static void main(String[] args)
{
StringBuilder word = new StringBuilder("cat");
findWords(word,0,1);
}
Solution:
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Main {
static List<String> resultList = new ArrayList<>();
static void computeResult(char[] s, int pos, String resultString) {
if (pos == 3) {
resultList.add(resultString);
return;
}
for (int i = 0; i < 3; ++i) {
if (!resultString.contains(String.valueOf(s[i]))) {
computeResult(s, pos + 1, resultString + s[i]);
}
}
}
public static void main(String... args) {
Scanner sc = new Scanner(System.in);
char[] s = sc.next().toCharArray();
sc.close();
computeResult(s, 0, "");
for(String str : resultList) {
System.out.println(str);
}
}
}
Explanation:
The recursion is done by the computeResult function. It starts with an empty string, then it iterates through all possible letters 'c', 'a' and 't', appending them to the resultString, now there are 3 strings and for each one of them the function computeResult is called again. Then it does the same thing and also adds only those letters to the resultString that haven't been added yet, so to 'c' we append 'a' resulting in 'ca' and 't', resulting in 'ct', I think the rest you can figure out yourself.
Note than this works if the letters are unique. If they are not, for example you are given the string 'tat', you can transform it into t1a1t2 and do the same procedure for the array ['t1', 'a1', 't2'], then remove the digits.
The algorithm I used is quite simple. Make each character the first character of the string and find combinations with other two characters. So for the characters c, a, t the combinations would be
c at
c ta
a ct
a tc
t ca
t ac
Code:
static void findWords(String str, int pos) {
if(str == null || pos < -1) {
return;
}
int len = str.length();
if(pos + 1 < len) {
findWords(str, pos + 1);
}
//find char swap positions
int pos1 = (pos + 1) % len;
int pos2 = (pos - 1 + len) % len;
char[] chars = str.toCharArray();
String str1 = new String(new char[] {chars[pos], chars[pos1], chars[pos2]});
String str2 = new String(new char[] {chars[pos], chars[pos2], chars[pos1]});
System.out.println(str1);
System.out.println(str2);
}
public static void main(String[] args) {
String word = new String("abc");
findWords(word, 0);
}
Here is a full working example with my comments to explain the algorithm.
This solution is based on backtracking. Read more about that here. Look at the problem as a tree. In your example the word is "cat". Here comes some ascii art...
cat
/ | \
Cat Act Tca
/ \ / \ / \
CAt CTa ACt ATc TCa TAc
At each pass, you fix a letter (I put it as a capital). The further down the tree you get the less there is that you can swap because you've fixed a certain amount of letters in place (at level 0 nothing is fixed, at level 1, one letter is fixed so a swap can be done, at level 2 you have no more swaps (the swap would be with itself), so the recursion reaches its base case.
public static void main(String[] args) {
// get all the permutations of a word with distinct letters
Set<String> permutations = getPermutations("cat");
// print the resulting set
System.out.println(permutations);
}
private static Set<String> getPermutations(String string) {
// recursive call to get a permutation of the given string and put it in
// the set of permutations (initially empty)
return permute(string, 0, string.length() - 1, new HashSet<String>());
}
private static Set<String> permute(String string, int left, int right, Set<String> set) {
if (left == right) {
// swap would be with itself so just add the string
// this is the base case
set.add(string);
} else {
for (int i = left; i <= right; i++) {
// indices are different, something can be swapped so swap it
string = swap(string, left, i);
// permute the swapped string starting from the next available character
permute(string, left + 1, right, set);
}
}
return set;
}
// utility method to carry out the swapping
// you could do this with primitive char[] and probably improve performance
// but for the sake of simplicity as it's just an exercise I used a
// StringBuilder
private static String swap(String in, int i, int j) {
char tmp1 = in.charAt(i);
char tmp2 = in.charAt(j);
StringBuilder sb = new StringBuilder(in);
// put the char at j in place of the char at i
sb.setCharAt(i, tmp2);
// and do the same the other way around
sb.setCharAt(j, tmp1);
return sb.toString();
}
I am trying to create a program that outputs ten lowercase letter characters - five vowels and five consonants. In order to do this, I have started by creating a char array with a range between 'a' and 'z' called letters[] with size 10. Once the array is filled, I will print the output with the use of a format string containing everything in the array.
My question is, how would I make the program output exactly five of each type (and keep the order of the characters printed completely random)? I have considered using the switch statement with a case each for consonants and vowels, but my ideas so far seem over-complicated and inelegant.
Code so far:
char letters[] = new char[10];
for(int i = 0; i < letters.length; i++){ //Open for
letters[i] = (char)(97 + Math.random() * 26);
char idx = letters[i];
System.out.printf("%s",idx);
} //End for
If you don't mind a somewhat more String-related solution, here is one. I am assuming that you don't want any consonant or vowel repeated in the output string, so this algorithm removes letters for consideration once they've been used. It also provides a bit more of a generic letter picker routine that's not really limited to vowels and consonants.
import java.lang.StringBuilder;
public class Shuffler {
public static String CONSONANTS = "bcdfghjklmnpqrstvwxyz";
public static String VOWELS = "aeiou";
/*
* Returns a new string that is a combination of the current string and 'count'
* characters from the source string (using any character in the source string
* no more than one time).
*/
public static String shuffleIntoString(String current, String source, int count) {
if (current == null || source == null || count < 0 || count > source.length()) {
System.out.println("Error in parameters to shuffleIntoString");
return null;
}
StringBuilder retval = new StringBuilder(current); // build up by inserting at random locations
StringBuilder depletedSource = new StringBuilder(source); // remove characters as they are used
for (int i = 0; i < count; i++) {
int pick = (int) (Math.random() * depletedSource.length());
int whereToInsert = (int) (Math.random() * retval.length());
retval = retval.insert(whereToInsert, depletedSource.charAt(pick));
depletedSource.deleteCharAt(pick);
}
return retval.toString();
}
public static void main(String[] args) {
Shuffler shuf = new Shuffler();
for (int i = 0; i < 10; i++) {
String result = shuf.shuffleIntoString("", shuf.CONSONANTS, 5);
result = shuf.shuffleIntoString(result, shuf.VOWELS, 5);
System.out.println(result);
}
}
}
And the output looks like this:
kqoibauzed
uhcawoerib
afdzoemius
yuagocibej
eiuhaokcyq
ouveiawrxn
uyaiveomxn
ruxeoalhij
uraliwfeoc
afoutiesmr
This will achieve what you desire if you are content with using ArrayLists. To generate the random chars you could generate a number within the index of the corresponding char Strings and add the value to the ArrayList. Collections is a helpful Class that you can use to shuffle the list.
List<Character> list = new ArrayList<>();
String consonants = "bcdfghjklmnpqrstvwxyz";
String vowels = "aeiou";
Random r = new Random();
for (int i = 0; i < 5; i++) {
list.add(consonants.charAt(r.nextInt(consonants.length()))); // Add consonant
list.add(vowels.charAt(r.nextInt(vowels.length()))); // Add vowel
}
Collections.shuffle(list);
for (Character c : list) {
System.out.println(c);
}
I don't seen any rules about duplicated but if you want you can remove latters from arrays after selection.
List<Character> vowels = Arrays.asList('a', 'e', 'i', 'o', 'u');
List<Character> consonants = new ArrayList<>();
for (char latter = 'a'; latter <= 'z'; latter++) {
if(!vowels.contains(latter)) {
consonants.add(latter);
}
}
final Random random = new Random();
int vowelsRemain = 5;
int consonantsRemain = 5;
List<Character> result = new ArrayList<>();
while (vowelsRemain > 0 && consonantsRemain > 0) {
final boolean generateVowel = random.nextBoolean();
final char randomLatter;
if(generateVowel) {
randomLatter = vowels.get(random.nextInt(vowels.size()));
vowelsRemain--;
} else {
randomLatter = consonants.get(random.nextInt(consonants.size()));
consonantsRemain--;
}
result.add(randomLatter);
}
while (vowelsRemain > 0) {
final Character randomVowel = vowels.get(random.nextInt(vowels.size()));
result.add(randomVowel);
vowelsRemain--;
}
while (consonantsRemain > 0) {
final Character randomConsonant = consonants.get(random.nextInt(consonants.size()));
result.add(randomConsonant);
consonantsRemain--;
}
System.out.println(result);
I have a long String with 48bit in Java. This string will be divided into 8 strings with a length of 6bit. Every string should be converted to an ASCII char. Therefore the Sixbit ASCII Code should be used.
Now I have a table with all the possible chars and the binary code for it. My first idea was to convert the binary string to the char by using a switch case and define a rule for every possibility, but this can't be the best option.
Is there some kind of a function, which I can use to convert this automatically and that I don't have to write a method with the switch?
public byte sixBitFromAscii(char asciiChar) {
if (asciiChar >= 0x60) {
System.out.println("Invalid character " + asciiChar);
return 0;
}
else {
return (byte)(asciiChar - 0x20);
}
}
public char asciiFromSixBit(byte sixBit) {
return (char) (sixBit + 0x20);
}
Ok, thanks to the clarification, and your posting the actual table, this becomes really simple. With the charset sorted, we can just convert directory and index into the array. Keep in mind, if you input was a String of 0/1s, you'd have to do some bit twiddling to get value (named n in this code). Otherwise, it would be the same.
public class sixbit {
static final char[] CHARSET =
{'#','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O',
'P','Q','R','S','T','U','V','W','X','Y','Z','[','\\',']','^',
'_',' ','!','"','#','$','%','&','\'','(',')','*','+',',','-',
'.','/','0','1','2','3','4','5','6','7','8','9',':',';','<',
'=','>','?'};
public static void main(String[] args) {
// Sample String of length 48, maybe up of 1s and 0s
String input = "010011010100000001000011001011001111010110010010" ;
System.out.println(input);
String[] parts = splitInput(input); // Split into 6-bit pieces
for(String sixbit: parts) {
int n = Integer.parseUnsignedInt(sixbit, 2);
System.out.printf("%s -> %c \n", sixbit,CHARSET[n]);
}
}
private static String[] splitInput(String input) {
String[] parts = new String[8]; // 48 bits, 6 bits each means we get 8 characters;
int current_part = 0;
int current_bit = 0;
StringBuilder sb;
while(current_bit < 48) {
sb = new StringBuilder();
for(int i=0; i < 6; i++) {
sb.append(input.charAt(current_bit));
current_bit++;
}
parts[current_part] = sb.toString();
current_part++;
}
return parts;
}
}
old version
Other than the loadLookupTable() method only including some randomly tossed together entries your table, this should do what you want.
import java.util.*;
public class sixbit {
static Map<String,Character> lookup = new HashMap<String,Character>();
public static void main(String[] args) {
loadLookupTable();
// Sample String of length 48, maybe up of 1s and 0s
String input = "111000111001100110101000110000110100111011110111" ;
System.out.println(input);
String[] parts = splitInput(input); // Split into 6-bit pieces
for(String sixbit: parts) {
char ch = lookup.get(sixbit); // Lookup each 6-bit String to get the corresponding character.
System.out.printf("%s -> %c \n", sixbit, ch);
}
}
private static String[] splitInput(String input) {
String[] parts = new String[8]; // 48 bits, 6 bits each means we get 8 characters;
int current_part = 0;
int current_bit = 0;
StringBuilder sb;
while(current_bit < 48) {
sb = new StringBuilder();
for(int i=0; i < 6; i++) {
sb.append(input.charAt(current_bit));
current_bit++;
}
parts[current_part] = sb.toString();
current_part++;
}
return parts;
}
private static void loadLookupTable() {
/* For each bit string you have in your table, add the corresponding character. It would be shorter code,
* and a touch faster to load this from an array, but it would take a bit of thought and wouldn't be as clear.
* Grab enough to work for this example, so that this program works. Just need to make sure the full lookup is loaded
* properly.
*/
lookup.put("100110", 'a');
lookup.put("100111", 'b');
lookup.put("101000", 'c');
lookup.put("110000", 'k');
lookup.put("110100", 'o');
lookup.put("110111", 'r');
lookup.put("111000", 's');
lookup.put("111001", 't');
// and so on...
lookup.put("111011", 'v');
lookup.put("111100", 'w');
lookup.put("111101", 'x');
lookup.put("111110", 'y');
lookup.put("111111", 'z');
}
}
Break the String into bytes (6-bits each with 2 bits of padding). Then just use an array mapping the byte values to the ASCII char value.
edit Ok, I misunderstood your question as you having raw binary data. Apparent you have a String of 1s and 0s, like "1010111" of length 48. The actual implementation is very different (and a lot easier). See my other answer. Sorry for the confusion.
I am using this function to generate a random password of length 11, as seen in this post:
import java.util.Random;
public class RandomPassword {
public static void main(String[] args){
RandomPassword r = new RandomPassword(11);
System.out.print(r.nextString());
}
private static final char[] symbols;
static {
StringBuilder tmp = new StringBuilder();
for (char ch = '0'; ch <= '9'; ++ch)
tmp.append(ch);
for (char ch = 'a'; ch <= 'z'; ++ch)
tmp.append(ch);
for (char ch = 'A'; ch <= 'Z'; ++ch)
tmp.append(ch);
symbols = tmp.toString().toCharArray();
}
private final Random random = new Random();
private final char[] buf;
public RandomPassword(int length) {
if (length < 1)
throw new IllegalArgumentException("length < 1: " + length);
buf = new char[length];
}
public String nextString() {
for (int idx = 0; idx < buf.length; ++idx)
buf[idx] = symbols[random.nextInt(symbols.length)];
return new String(buf);
}
}
However I need to modify it so that I can guarantee at least one capital letter, one number and one lowercase letter. Right now there is the possibility that the password could contain all caps/lowercase/numbers and we need at least one of each to be accepted by AD. Any help is appreciated, thanks.
***I am told that it would be best to loop through in nextString() like this:
public String nextString() {
for (int idx = 0; idx < buf.length; ++idx)
if(buf[buf.length%3].equals(num/lower/cap)){
buf[idx] = symbols[random.nextInt(symbols.length)];
}
.
.
.
return new String(buf);
}
What do you think?
Create a truly random password
See if the random password meets your requirements using a regular expression
If not, pick a random char from the password and modify it to be a randomly chosen
symbol (or number, or uppercase letter)
This would prevent loops and would also have the benefit of being truly random.
Or, if you're ok with losing some entropy you could:
Create four random strings: lowercase (length: 5), uppercase (4), number (1) and symbol (1)
Concatenate the strings
Shuffle the string with Collections.shuffle
I would recommend a regular expresion searching for a set of predifined characters/numbers uppercase/lowercase and a error message
public String getPassword(){
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG", "SUN");
byte[] salt = new byte[16];
sr.nextBytes(salt);
return wellformedPassword(salt.toString()) ? salt.toString() : secured(salt.toString());
}
public String secured(String pass){
return string1.replaceFirst(Pattern.quote("[a-z]", "Z");
}
public boolean wellformedPassword(String pass){
return checkRegExp(pass, "\\d")
&& checkRegExp(pass, "[A-Z]")
&& checkRegExp(pass, "[a-z]");
}
public boolean checkRegExp(String str, String pattern){
Pattern p = Pattern.compile(pattern);
Matcher n = p.matcher(str);
return n.find();
}
SHA assure you lowercase letters and numbers, then you just need to turn, one (in my case) or more to upper.
this is a dummy approach wich can be improved. Share your code so i cant edit later my answer for anyone else.
You could get that char and turn it to upper instead of Z but i guess with this you can get started.
Loop over the characters in the array to ensure that each character class is contained within. Then, if it fails, just generate a new random string. This ensures that all are contained and will not fail to validate very often.
This "cheats" (is weaker than it could be), but it meets the usual requirements (or can be modified to meet them):
import java.util.Random;
public class Password {
private static final String UPPER = "ABCDEFGHIJKLMNPQRSTUVWXYZ";
private static final String LOWER = "abcdefghijklmnpqrstuvwxyz";
private static final String NUMBER = "123456789";
private static final String SPECIAL = "!##$%&*+?";
private Random randGen = new Random();
public static void main(String[] argv) {
Password me = new Password();
for (int i = 0; i <= 10; i++) {
me.printPassword();
}
}
private void printPassword() {
StringBuffer buf = new StringBuffer();
buf.append(LOWER.charAt(Math.abs(randGen.nextInt()) % LOWER.length()));
buf.append(LOWER.charAt(Math.abs(randGen.nextInt()) % LOWER.length()));
buf.append(NUMBER.charAt(Math.abs(randGen.nextInt()) % NUMBER.length()));
for (int i = 0; i <= 4; i++) {
buf.append(LOWER.charAt(Math.abs(randGen.nextInt()) % LOWER.length()));
}
buf.append(UPPER.charAt(Math.abs(randGen.nextInt()) % UPPER.length()));
buf.append(LOWER.charAt(Math.abs(randGen.nextInt()) % LOWER.length()));
System.out.println(buf.toString());
}
}
I had another algorithm that was better, but lost it.
(I like to print out multiple "suggestions" and then pick the one that seems easiest to remember.)
I really don't know how reliable it is but a try
List<Character> listOfUpperCaseLetter = new ArrayList<Character>();
for(int i = 65;i<91;i++){
char ch = (char)i;
listOfUpperCaseLetter.add(ch);
}
List<Character> listOfLowerCaseLetter = new ArrayList<Character>();
for(int i = 97;i<123;i++){
char ch = (char)i;
listOfLowerCaseLetter.add(ch);
}
List<Integer> listOfInt = new ArrayList<Integer>();
for(int i =0;i<10;i++){
listOfInt.add(i);
}
StringBuilder br = new StringBuilder();
Collections.shuffle(listOfLowerCaseLetter);
Collections.shuffle(listOfUpperCaseLetter);
Collections.shuffle(listOfInt);
br.append(listOfUpperCaseLetter.get(0));
br.append(listOfLowerCaseLetter.get(1));
br.append(listOfLowerCaseLetter.get(3));
br.append(listOfInt.get(1));
br.append(listOfInt.get(0));
br.append(listOfLowerCaseLetter.get(2));
br.append(listOfUpperCaseLetter.get(1));
br.append(listOfLowerCaseLetter.get(0));
br.append(listOfUpperCaseLetter.get(2));
br.append(listOfInt.get(2));
System.out.println(br.toString());
I simply added an if/else statement saying to add certain members of the symbols array (0-10, 11-35, 36-61). This guarantees what is needed. Sometimes the simplest answer is the best answer. Thanks for the ideas.
if (idx == 0){
buf[idx] = symbols[random.nextInt(10)];
}else if (idx == 1){
buf[idx] = symbols[10 + random.nextInt(35-10+1)];
}else if(idx == 2){
buf[idx] = symbols[36 + random.nextInt(61-36+1)];
}else{
buf[idx] = symbols[random.nextInt(symbols.length)];
}