Does Java have any functionality to generate random characters or strings? Or must one simply pick a random integer and convert that integer's ascii code to a character?
To generate a random char in a-z:
Random r = new Random();
char c = (char)(r.nextInt(26) + 'a');
There are many ways to do this, but yes, it involves generating a random int (using e.g. java.util.Random.nextInt) and then using that to map to a char. If you have a specific alphabet, then something like this is nifty:
import java.util.Random;
//...
Random r = new Random();
String alphabet = "123xyz";
for (int i = 0; i < 50; i++) {
System.out.println(alphabet.charAt(r.nextInt(alphabet.length())));
} // prints 50 random characters from alphabet
Do note that java.util.Random is actually a pseudo-random number generator based on the rather weak linear congruence formula. You mentioned the need for cryptography; you may want to investigate the use of a much stronger cryptographically secure pseudorandom number generator in that case (e.g. java.security.SecureRandom).
You could also use the RandomStringUtils from the Apache Commons project:
Dependency:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.8.1</version>
</dependency>
Usages:
RandomStringUtils.randomAlphabetic(stringLength);
RandomStringUtils.randomAlphanumeric(stringLength);
private static char rndChar () {
int rnd = (int) (Math.random() * 52); // or use Random or whatever
char base = (rnd < 26) ? 'A' : 'a';
return (char) (base + rnd % 26);
}
Generates values in the ranges a-z, A-Z.
String abc = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char letter = abc.charAt(rd.nextInt(abc.length()));
This one works as well.
In following 97 ascii value of small "a".
public static char randomSeriesForThreeCharacter() {
Random r = new Random();
char random_3_Char = (char) (97 + r.nextInt(3));
return random_3_Char;
}
in above 3 number for a , b , c or d and if u want all character like a to z then you replace 3 number to 25.
You could use generators from the Quickcheck specification-based test framework.
To create a random string use anyString method.
String x = anyString();
You could create strings from a more restricted set of characters or with min/max size restrictions.
Normally you would run tests with multiple values:
#Test
public void myTest() {
for (List<Integer> any : someLists(integers())) {
//A test executed with integer lists
}
}
using dollar:
Iterable<Character> chars = $('a', 'z'); // 'a', 'b', c, d .. z
given chars you can build a "shuffled" range of characters:
Iterable<Character> shuffledChars = $('a', 'z').shuffle();
then taking the first n chars, you get a random string of length n. The final code is simply:
public String randomString(int n) {
return $('a', 'z').shuffle().slice(n).toString();
}
NB: the condition n > 0 is cheched by slice
EDIT
as Steve correctly pointed out, randomString uses at most once each letter. As workaround
you can repeat the alphabet m times before call shuffle:
public String randomStringWithRepetitions(int n) {
return $('a', 'z').repeat(10).shuffle().slice(n).toString();
}
or just provide your alphabet as String:
public String randomStringFromAlphabet(String alphabet, int n) {
return $(alphabet).shuffle().slice(n).toString();
}
String s = randomStringFromAlphabet("00001111", 4);
This is a simple but useful discovery. It defines a class named RandomCharacter with 5 overloaded methods to get a certain type of character randomly. You can use these methods in your future projects.
public class RandomCharacter {
/** Generate a random character between ch1 and ch2 */
public static char getRandomCharacter(char ch1, char ch2) {
return (char) (ch1 + Math.random() * (ch2 - ch1 + 1));
}
/** Generate a random lowercase letter */
public static char getRandomLowerCaseLetter() {
return getRandomCharacter('a', 'z');
}
/** Generate a random uppercase letter */
public static char getRandomUpperCaseLetter() {
return getRandomCharacter('A', 'Z');
}
/** Generate a random digit character */
public static char getRandomDigitCharacter() {
return getRandomCharacter('0', '9');
}
/** Generate a random character */
public static char getRandomCharacter() {
return getRandomCharacter('\u0000', '\uFFFF');
}
}
To demonstrate how it works let's have a look at the following test program displaying 175 random lowercase letters.
public class TestRandomCharacter {
/** Main method */
public static void main(String[] args) {
final int NUMBER_OF_CHARS = 175;
final int CHARS_PER_LINE = 25;
// Print random characters between 'a' and 'z', 25 chars per line
for (int i = 0; i < NUMBER_OF_CHARS; i++) {
char ch = RandomCharacter.getRandomLowerCaseLetter();
if ((i + 1) % CHARS_PER_LINE == 0)
System.out.println(ch);
else
System.out.print(ch);
}
}
}
and the output is:
if you run one more time again:
I am giving credit to Y.Daniel Liang for his book Introduction to Java Programming, Comprehensive Version, 10th Edition, where I cited this knowledge from and use in my projects.
Note: If you are unfamiliar with overloaded methhods, in a nutshell Method Overloading is a feature that allows a class to have more than one method having the same name, if their argument lists are different.
Take a look at Java Randomizer class.
I think you can randomize a character using the randomize(char[] array) method.
My propose for generating random string with mixed case like: "DthJwMvsTyu".
This algorithm based on ASCII codes of letters when its codes a-z (97 to 122) and A-Z (65 to 90) differs in 5th bit (2^5 or 1 << 5 or 32).
random.nextInt(2): result is 0 or 1.
random.nextInt(2) << 5: result is 0 or 32.
Upper A is 65 and lower a is 97. Difference is only on 5th bit (32) so for generating random char we do binary OR '|' random charCaseBit (0 or 32) and random code from A to Z (65 to 90).
public String fastestRandomStringWithMixedCase(int length) {
Random random = new Random();
final int alphabetLength = 'Z' - 'A' + 1;
StringBuilder result = new StringBuilder(length);
while (result.length() < length) {
final char charCaseBit = (char) (random.nextInt(2) << 5);
result.append((char) (charCaseBit | ('A' + random.nextInt(alphabetLength))));
}
return result.toString();
}
Here is the code to generate random alphanumeric code. First you have to declare a string of allowed characters what you want to include in random number.and also define max length of string
SecureRandom secureRandom = new SecureRandom();
String CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789";
StringBuilder generatedString= new StringBuilder();
for (int i = 0; i < MAXIMUM_LENGTH; i++) {
int randonSequence = secureRandom .nextInt(CHARACTERS.length());
generatedString.append(CHARACTERS.charAt(randonSequence));
}
Use toString() method to get String from StringBuilder
polygenelubricants' answer is also a good solution if you only want to generate Hex values:
/** A list of all valid hexadecimal characters. */
private static char[] HEX_VALUES = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'A', 'B', 'C', 'D', 'E', 'F' };
/** Random number generator to be used to create random chars. */
private static Random RANDOM = new SecureRandom();
/**
* Creates a number of random hexadecimal characters.
*
* #param nValues the amount of characters to generate
*
* #return an array containing <code>nValues</code> hex chars
*/
public static char[] createRandomHexValues(int nValues) {
char[] ret = new char[nValues];
for (int i = 0; i < nValues; i++) {
ret[i] = HEX_VALUES[RANDOM.nextInt(HEX_VALUES.length)];
}
return ret;
}
In fact mentioned methods don't generate real random char. To generate real random char you should give it a random seed! in example time in millisecond. this code generate 10 random char and then Convert it to String:
import java.util.Random;
public class MyClass {
public static void main() {
String randomKey;
char[] tempArray={0,0,0,0,0,0,0,0,0,0}; //ten characters
long seed=System.currentTimeMillis();
Random random=new Random(seed);
for (int aux=0; aux<10;aux++){
tempArray[aux]=(char) random.nextInt(255);
System.out.println(tempArray[aux]);
}
randomKey=String.copyValueOf(tempArray);
System.out.println(randomKey);
}
}
I use this:
char uppercaseChar = (char) ((int)(Math.random()*100)%26+65);
char lowercaseChar = (char) ((int)(Math.random()*1000)%26+97);
java.util.Random is the more effective one I have tried out so far, having a precision of 98.65% uniqueness.
I have provided bellow some tests which generate 10000 batches of a hundred 2 alphanumeric chars strings and calculates the average.
Other random tools were RandomStringUtils from commons.lang3 and java.util.Math.
public static void main(String[] args) {
int unitPrintMarksTotal = 0;
for (int i = 0; i < 10000; i++) {
unitPrintMarksTotal += generateBatchOfUniquePrintMarks(i);
}
System.out.println("The precision across 10000 runs with 100 item batches is: " + (float) unitPrintMarksTotal / 10000);
}
private static int generateBatchOfUniquePrintMarks(int batch) {
Set<String> printMarks = new HashSet<>();
for (int i = 0; i < 100; i++) {
printMarks.add(generatePrintMarkWithJavaUtil());
}
System.out.println("Batch " + batch + " Unique number of elements is " + printMarks.size());
return printMarks.size();
}
// the best so far => 98.65
// with 3 chars => 99.98
// with 4 chars => 99.9997
private static String generatePrintMarkWithJavaUtil() {
int leftLimit = 48; // numeral '0'
int rightLimit = 122; // letter 'z'
int targetStringLength = 2;
String printMark;
do {
printMark = new Random().ints(leftLimit, rightLimit + 1)
.filter(i -> (i <= 57 || i >= 65) && (i <= 90 || i >= 97))
.limit(targetStringLength)
.collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append)
.toString();
} while (!isValid(printMark));
return printMark;
}
// 95.46
private static String generatePrintMarkWithCommonsLang3() {
String printMark;
do {
printMark = RandomStringUtils.randomAlphanumeric(2).toUpperCase();
} while (!isValid(printMark));
return printMark;
}
// 95.92
private static String generatePrintMarkWithMathRandom() {
final String ALPHA_NUMERIC_STRING = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
StringBuilder printMark;
do {
printMark = new StringBuilder();
int i = (int) (Math.random() * ALPHA_NUMERIC_STRING.length());
printMark.append(ALPHA_NUMERIC_STRING.charAt(i));
int j = (int) (Math.random() * ALPHA_NUMERIC_STRING.length());
printMark.append(ALPHA_NUMERIC_STRING.charAt(j));
} while (!isValid(printMark.toString()));
return printMark.toString();
}
private static boolean isValid(final String printMark) {
return true;
}
I simply want to tell you to use UUID.randomUUID() and toString() as its simplest way i also used
If you don't mind adding a new library in your code you can generate characters with MockNeat (disclaimer: I am one of the authors).
MockNeat mock = MockNeat.threadLocal();
Character chr = mock.chars().val();
Character lowerLetter = mock.chars().lowerLetters().val();
Character upperLetter = mock.chars().upperLetters().val();
Character digit = mock.chars().digits().val();
Character hex = mock.chars().hex().val();
public static void main(String[] args) {
// System.out.println("Enter a number to changeit at char ");
Random random = new Random();
int x = random.nextInt(26)+65; //0 to 25
System.out.println((char)x);
}
Random randomGenerator = new Random();
int i = randomGenerator.nextInt(256);
System.out.println((char)i);
Should take care of what you want, assuming you consider '0,'1','2'.. as characters.
Related
I am currently a beginner in programming and I am trying to write a program in java to convert binary in hexadecimal numbers.
I know that the program will have to divide the number in groups of 4 and convert them to hexadecimal.
Ex: 11101111 (b2) --> E + F --- EF
However, since I used ints to do the conversion of the numbers, I'm stuck when I need to print a letter because it is a String.
Can someone point me to the right way? What am I doing wrong? I've also tried another version with an auxiliary array to store each group of 4 digits but I can't manage to insert a proper dimension to the array.
Unfortunately I am not allowed to use any function other than Scanner and Math, the method lenght and charAt and the basic stuff. I can't modify the public static line either.
EDIT: So after your inputs and so many tries, I managed to get this code. However it gives me an error if I insert too many numbers, eg: 0111011010101111. I've tried to change int to double but that didn't fix the problem.
import java.util.Scanner;
public class Bin2HexString {
public static void main(String[] args) {
Scanner keyb = new Scanner(System.in);
System.out.println("Valor?");
int vlr = keyb.nextInt();
String num = "";
int aux = vlr;
// Hexadecimal numbers
String arr[] = {"0","1","2","3","4","5","6","7","8","9","A", "B", "C", "D", "E", "F"};
String bits[] = {"0000","0001","0010","0011","0100","0101","0110","0111","1000","1001","1010","1011","1100","1101","1110","1111"};
String letters = "";
//Divide in groups of 4
int r;
for (; aux > 0; ) {
r = aux % 10000;
aux = aux / 10000;
num = "" + r;
for (;num.length() < 4;) { //add missing zeros
String zero = "0";
num = zero + num;
}
int charint = 0,bitint = 0;
for (int i = 0; i < arr.length;i++) {
String aux2 = bits[i];
String aux3 = arr[i];
for (int j = 0; j < num.length();j++) { // compare each group with arr[i]
char charvl = num.charAt(j);
char bitsvl = aux2.charAt(j);
charint = ((int) (charvl)-'0');
bitint = ((int) (bitsvl) - '0');
if (bitint != charint)
break;
}
if (bitint == charint)
letters = aux3 + "" + letters;
}
}
System.out.println(letters);
}
}
Having thought about this for a while to determine the most effective and useful way to do this is to write methods which convert a string from any base between 2 and 16 to an int and back to a string again.
This way you have useful methods for other things. And note that they methods can be easily changed and names to simply hard code the desired radix into the method to limit it to binary and hex methods.
The indexOf utility method was written to avoid using the builtin String method.
final static String hex = "0123456789ABCDEF";
static int stringToInt(String str, int radix) {
if (radix < 2 || radix > 16) {
System.out.println("Base must be between 2 and 16 inclusive");
return -1;
}
int v = 0;
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
int idx = indexOf(hex, c);
if (idx < 0 || idx > radix) {
System.out.println("Illegal character in string (" + c + ")");
}
v = v * radix + idx;
}
return v;
}
static String intToBase(int v, int radix) {
if (radix < 2 || radix > 16) {
System.out.println("Base must be between 2 and 16 inclusive");
return null;
}
String s = "";
while (v > 0) {
int idx = v % radix;
s = hex.charAt(idx) + s;
v /= radix;
}
return s;
}
static int indexOf(String str, char c) {
for (int i = 0; i < str.length(); i++) {
if (str.charAt(i) == c) {
return i;
}
}
return -1;
}
And here is an example of their use.
// generate some test data
Random r = new Random(23);
String[] bitStrings =
r.ints(20, 20, 4000).mapToObj(Integer::toBinaryString).toArray(
String[]::new);
for (String bitstr : bitStrings) {
int v = baseToInt(bitstr, 2);
String hex = intToBase(v, 16);
System.out.printf("%12s = %s%n", bitstr, hex);
}
Which prints the following:
101110000011 = B83
111001111100 = E7C
10001110111 = 477
100110001111 = 98F
111001010 = 1CA
111001001111 = E4F
111000011010 = E1A
100001010010 = 852
11011001101 = 6CD
111010010111 = E97
Just some quick notes:
First this is wrong:
//Divide in groups of 4
for (; aux > 0; ) {
r = aux % 10000;
aux = aux / 10000;
Not at all what you want to do. Try it by hand and see what happens. Take a simple number that you know the answer to, and try it. You won't get the right answer. A good test is 17, which is 11 hex.
Try this instead: convert directly to the base you want. Hex is base 16 (its radix is 16), so you use 16 instead.
//Divide in groups of 4
for (; aux > 0; ) {
r = aux % 16;
aux = aux / 16;
Try those numbers with the test case, which is 17, and see what you get. That will get you much closer.
I'm assuming by "without methods" in the title, you are attempting to write your own integer parsing method instead of using Scanner.nextInt(int radix). In that case, my first advice would be work with a string instead of an integer - you'll be able to handle larger numbers and you can simply make an array of substrings (length 4) to convert to letters.
So, if you use the string approach - first scan in a string, not an int. Then I'd recommend a hash table with the 4-bit strings as keys and the hexadecimal equivalents as values. That should make calculation quite fast.
e.g.
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
public class HashMapBin2Hex
{
public static void main(String[] args)
{
//Read the string in
Scanner sc = new Scanner(System.in);
System.out.println("Binary number?");
String bin = sc.nextLine();
//Pad the bitstring with leading zeros to make a multiple of four
String zeros = "";
int i;
if (bin.length() % 4 != 0)
{
for (i = 0; i < 4 - (bin.length() % 4); i++)
{
zeros += "0";
}
}
bin = zeros + bin;
//Split the padded string into 4-bit chunks
String[] chunks = new String[bin.length() / 4];
for (i = 0; (i * 4) < bin.length() - 1; i++)
{
chunks[i] = bin.substring(i * 4, (i * 4) + 4);
}
//Convert the chunks to hexadecimal
String hex = "";
Map<String, String> bin2hex = new HashMap<>();
bin2hex.put("0000", "0");
bin2hex.put("0001", "1");
bin2hex.put("0010", "2");
bin2hex.put("0011", "3");
bin2hex.put("0100", "4");
bin2hex.put("0101", "5");
bin2hex.put("0110", "6");
bin2hex.put("0111", "7");
bin2hex.put("1000", "8");
bin2hex.put("1001", "9");
bin2hex.put("1010", "A");
bin2hex.put("1011", "B");
bin2hex.put("1100", "C");
bin2hex.put("1101", "D");
bin2hex.put("1110", "E");
bin2hex.put("1111", "F");
for (String s : chunks)
{
hex += bin2hex.get(s);
}
System.out.println("Hexadecimal: " + hex);
sc.close();
}
}
Further iterations could have some error checking to prevent catastrophic failure in the case of characters other than 0 or 1.
And of course, if you're fine with the other way (builtins), the following is far easier and more robust (ie will throw an exception if the string contains anything other than 0s and 1s):
import java.util.Scanner;
public class BuiltinBin2Hex
{
public static void main(String[] args)
{
//Read the binary number in
Scanner sc = new Scanner(System.in);
System.out.println("Binary number?");
int bin = sc.nextInt(2);
//And print as hexadecimal
System.out.println("Hexadecimal: " + Integer.toString(bin, 16));
sc.close();
}
}
I want to add two character arrays and store the result as characters in another character array.
The addition involves addition of two english letters from the two arrays as operands.
The addition will wrap around z back to a .
eg.
Input:Array1 and Array 2 and output is Array 3
Array 1 :abcdeyz
Array 2 :aaaaaaa
Array 3 :bcdefza
Below is a part of my code which is not working.
Kindly suggest any changes
int c = 0;
char array3[] = new char[count] ;
for(int a=0;a<array1.length;a++)
{
for(int b=0;b<array2.length;b++)
{
int temp = (array1[a] + array2[b]) % 26 ;
array3[c] = (char) temp ;
c++ ;
}
}
Hint - value of 'a' is not 0
The issue is in the line -
int temp = (array1[a] + array2[b]) % 26 ;
Here is the modified code (assuming all characters are lower case)-
int c = 0;
char array3[] = new char[count] ;
for(int a=0;a<array1.length;a++)
{
for(int b=0;b<array2.length;b++)
{
int temp = ( (array1[a]-'a') + (array2[b]-'a')) % 26 ;
array3[c] = (char) (temp+'a') ;
c++ ;
}
}
Using the modulo of 26 is a good way of handling a-z to 1-26 conversion. This way your program can be agnostic about the actual ASCII character numbers.
Some other concerns:
Case Insensitivity. I would recommend converting your letters to lowercase before processing them.
Handling of exceptional cases. What if your arrays are different lengths? Or what if they have a character that isn't a
letter?
The below code is one way to handle these things.
public static int letterToInt(char letter) {
char letterToConvert = Character.toLowerCase(letter);
int codeForA = (int)'a';
int numberOfLetter = ((int)letterToConvert) - codeForA + 1;
if(numberOfLetter < 1 || numberOfLetter > 26) {
throw new IllegalArgumentException(
"The character argument can only be a-z or A-Z, but was '" + letter + "'");
}
return numberOfLetter;
}
public static char intToLetter(int number) {
if(number < 1 || number > 26) {
throw new IllegalArgumentException(
"The number can only be 1-26, but was " + number);
}
int codeForA = (int)'a';
return (char)(codeForA + number - 1);
}
public static char addLetters(char letter1, char letter2) {
int numberFromAddedLetters =
letterToInt(letter1) + letterToInt(letter2);
int modulo = numberFromAddedLetters % 26;
return intToLetter(modulo == 0 ? 26 : modulo);
}
public static char[] addLetterArrays(char[] array1, char[] array2) {
char[] longerArray;
char[] shorterArray;
if(array1.length >= array2.length) {
longerArray = array1;
shorterArray = array2;
} else {
longerArray = array2;
shorterArray = array1;
}
char[] addedLetters = new char[longerArray.length];
for(int index = 0; index < longerArray.length; index++) {
if(index < shorterArray.length) {
addedLetters[index] = addLetters(longerArray[index], shorterArray[index]);
} else {
addedLetters[index] = longerArray[index];
}
}
return addedLetters;
}
// Test it out
public static void main(String[] args) {
char[] letters1 = "abcdeyz".toCharArray();
char[] letters2 = "aaaaaaa".toCharArray();
// Prints [b, c, d, e, f, z, a]
System.out.println(Arrays.toString(addLetterArrays(letters1, letters2)));
}
This is a fixed and working example on how to do this:
public static void main(String[] args) {
char[] array1 = new char[] {'a', 'b', 'c', 'd', 'e', 'y', 'z'};
char[] array2 = new char[] {'a', 'a', 'a', 'a', 'a', 'a', 'a'};
char[] array3 = new char[array1.length];
for (int i = 0; i < array1.length; i++) {
array3[i] = toChar((toInt(array1[i]) + toInt(array2[i]) + 1) % 26);
}
System.out.println(Arrays.toString(array3));
}
private static int toInt(char chr) {
return chr - 'a';
}
private static char toChar(int value) {
return (char)(value + 'a');
}
There are some thinks to notice here (except the - 'a' part, the other answers mentioned that already):
you only need one loop for this task. If you use 2 nested loops, then you'll add each letter of array1 with every letter of array2. And you'll a larger array3. And since the result doesn't match the desired result ... :)
the + 1 in toInt(array2[i]) + 1 is necessary, because char - 'a' is "zero-based". Therefore 'a' + 'b' would result in 'b' and not 'c', because you'll calculate 0 + 1 (which will be 'b' if you "convert" it back to char by adding 'a') (I hope this is understandable expressed :D)
it is necessary that array2 has at least the same length as 'array1'. It is almost like padding in cryptography. (I've omitted the padding part to keep this code short)
Write this:
int temp = (((array1[a] - 'a') + (array2[b] - 'a')) % 26) + 'a';
what this does is convert both characters into their respective place in the alphabet, perform addition modulo the number of characters in the alphabet for the wraparound effect, and convert back to the correct ascii value.
Note that your code was having trouble because you were acting as though the alphabet's ascii values were their respective places in the alphabet itself, which is incorrect.
I would like to be able to generate all possible strings from a given length, and I frankly don't know how to code that. So for further explanation, I and a friend would like to demonstrate some basic hacking techniques, so bruteforcing comes up. Of course, he will be my victim, no illegal thing there.
However, the only thing he told me is that his PW will be 4-char-long, but I'm pretty sure his PW won't be in any dictionnary, that would be toi easy.
So I came up with the idea of generating EVERY 4-char-long-string possible, containing a-z characters (no caps).
Would someone have a lead to follow to code such an algorithm ? I don't really bother with performances, if it takes 1 night to generate all PW, that's no problem.
Don't forget, that's only on demonstration purposes.
You can do it just how you'd do it with numbers. Start with aaaa. Then increment the 'least significant' part, so aaab. Keep going until you get to aaaz. Then increment to aaba. Repeat until you get to zzzz.
So all you need to do is implement is
String getNext(String current)
To expand on this; It possibly isnt the quickest way of doing things, but it is the simplest to get right.
As the old adage goes - 'first make it right, then make it fast'. Getting a working implementation that passes all your tests (you do have tests, right?) is what you do first. You then rewrite it to make it fast, using your tests as reassurance you're not breaking the core functionality.
The absolutely simplest way is to use four nested loops:
char[] pw = new char[4];
for (pw[0] = 'a' ; pw[0] <= 'z' ; pw[0]++)
for (pw[1] = 'a' ; pw[1] <= 'z' ; pw[1]++)
for (pw[2] = 'a' ; pw[2] <= 'z' ; pw[2]++)
for (pw[3] = 'a' ; pw[3] <= 'z' ; pw[3]++)
System.out.println(new String(pw));
This does not scale well, because adding extra characters requires adding a level of nesting. Recursive approach is more flexible, but it is harder to understand:
void findPwd(char[] pw, int pos) {
if (pos < 0) {
System.out.println(new String(pwd));
return;
}
for (pw[pos] = 'a' ; pw[pos] <= 'z' ; pw[pos]++)
findPwd(pw, pos-1);
}
Call recursive method like this:
char[] pw = new char[4];
findPwd(pw, 3);
private static void printAllStringsOfLength(int len) {
char[] guess = new char[len];
Arrays.fill(guess, 'a');
do {
System.out.println("Current guess: " + new String(guess));
int incrementIndex = guess.length - 1;
while (incrementIndex >= 0) {
guess[incrementIndex]++;
if (guess[incrementIndex] > 'z') {
if (incrementIndex > 0) {
guess[incrementIndex] = 'a';
}
incrementIndex--;
}
else {
break;
}
}
} while (guess[0] <= 'z');
}
public class GenerateCombinations {
public static void main(String[] args) {
List<Character> characters = new ArrayList<Character>();
for (char c = 'a'; c <= 'z'; c++) {
characters.add(c);
}
List<String> allStrings = new ArrayList<String>();
for (Character c : characters) {
for (Character d : characters) {
for (Character e : characters) {
for (Character f : characters) {
String s = "" + c + d + e + f;
allStrings.add(s);
}
}
}
}
System.out.println(allStrings.size()); // 456 976 combinations
}
}
This is something you can do recursively.
Lets define every (n)-character password the set of all (n-1)-character passwords, prefixed with each of the letters a thru z. So there are 26 times as many (n)-character passwords as there are (n-1)-character passwords. Keep in mind that this is for passwords consisting of lower-case letters. Obviously, you can increase the range of each letter quite easily.
Now that you've defined the recursive relationship, you just need the terminating condition.
That would be the fact that there is only one (0)-character password, that being the empty string.
So here's the recursive function:
def printNCharacterPasswords (prefix, num):
if num == 0:
print prefix
return
foreach letter in 'a'..'z':
printNCharacterPasswords (prefix + letter, num - 1)
to be called with:
printNCharacterPasswords ("", 4)
And, since Python is such a wonderful pseudo-code language, you can see it in action with only the first five letters:
def printNCharacterPasswords (prefix, num):
if num == 0:
print prefix
return
for letter in ('a', 'b', 'c', 'd', 'e'):
printNCharacterPasswords (prefix + letter, num - 1)
printNCharacterPasswords ("", 2)
which outputs:
aa
ab
ac
ad
ae
ba
bb
bc
bd
be
ca
cb
cc
cd
ce
da
db
dc
dd
de
ea
eb
ec
ed
ee
A aroth points out, using a digit counter approach is faster. To make this even faster, you can use a combination of an inner loop for the last digit and a counter for the rest (so the number of digits can be variable)
public static void main(String... args) {
long start = System.nanoTime();
int letters = 26;
int count = 6;
final int combinations = (int) Math.pow(letters, count);
char[] chars = new char[count];
Arrays.fill(chars, 'a');
final int last = count - 1;
OUTER:
while (true) {
for (chars[last] = 'a'; chars[last] <= 'z'; chars[last]+=2) {
newComination(chars);
chars[last]++;
newComination(chars);
}
UPDATED:
{
for (int i = last - 1; i >= 0; i--) {
if (chars[i]++ >= 'z')
chars[i] = 'a';
else
break UPDATED;
}
// overflow;
break OUTER;
}
}
long time = System.nanoTime() - start;
System.out.printf("Took %.3f seconds to generate %,d combinations%n", time / 1e9, combinations);
}
private static void newComination(char[] chars) {
}
prints
Took 0.115 seconds to generate 308,915,776 combinations
Note: the loop is so simple, its highly likely that the JIT can eliminate key pieces of code (after in-lining newCombination) and the reason its so fast is its not really calculating every combination.
A simpler way to generate combinations.
long start = System.nanoTime();
int letters = 26;
int count = 6;
final int combinations = (int) Math.pow(letters, count);
StringBuilder sb = new StringBuilder(count);
for (int i = 0; i < combinations; i++) {
sb.setLength(0);
for (int j = 0, i2 = i; j < count; j++, i2 /= letters)
sb.insert(0, (char) ('a' + i2 % letters));
// System.out.println(sb);
}
long time = System.nanoTime() - start;
System.out.printf("Took %.3f seconds to generate %,d combinations%n", time / 1e9, combinations);
prints
aaaa
aaab
aaac
....
zzzx
zzzy
zzzz
Took 0.785 seconds to generate 456,976 combinations
It spends most of its time waiting for the screen to update. ;)
If you comment out the line which prints the combinations, and increase the count to 5 and 6
Took 0.671 seconds to generate 11,881,376 combinations
Took 15.653 seconds to generate 308,915,776 combinations
public class AnagramEngine {
private static int[] anagramIndex;
public AnagramEngine(String str) {
AnagramEngine.generate(str);
}
private static void generate(String str) {
java.util.Map<Integer, Character> anagram = new java.util.HashMap<Integer, Character>();
for(int i = 0; i < str.length(); i++) {
anagram.put((i+1), str.charAt(i));
}
anagramIndex = new int[size(str.length())];
StringBuffer rev = new StringBuffer(AnagramEngine.start(str)+"").reverse();
int end = Integer.parseInt(rev.toString());
for(int i = AnagramEngine.start(str), index = 0; i <= end; i++){
if(AnagramEngine.isOrder(i))
anagramIndex[index++] = i;
}
for(int i = 0; i < anagramIndex.length; i++) {
StringBuffer toGet = new StringBuffer(anagramIndex[i] + "");
for(int j = 0; j < str.length(); j++) {
System.out.print(anagram.get(Integer.parseInt(Character.toString(toGet.charAt(j)))));
}
System.out.print("\n");
}
System.out.print(size(str.length()) + " iterations");
}
private static boolean isOrder(int num) {
java.util.Vector<Integer> list = new java.util.Vector<Integer>();
String str = Integer.toString(num);
char[] digits = str.toCharArray();
for(char vecDigits : digits)
list.add(Integer.parseInt(Character.toString(vecDigits)));
int[] nums = new int[str.length()];
for(int i = 0; i < nums.length; i++)
nums[i] = i+1;
for(int i = 0; i < nums.length; i++) {
if(!list.contains(nums[i]))
return false;
}
return true;
}
private static int start(String str) {
StringBuffer num = new StringBuffer("");
for(int i = 1; i <= str.length(); i++)
num.append(Integer.toString(i));
return Integer.parseInt(num.toString());
}
private static int size(int num) {
int size;
if(num == 1) {
return 1;
}
else {
size = num * size(num - 1);
}
return size;
}
public static void main(final String[] args) {
final java.util.Scanner sc = new java.util.Scanner(System.in);
System.out.printf("\n%s\t", "Entered word:");
String word = sc.nextLine();
System.out.printf("\n");
new AnagramEngine(word);
}
}
Put all the characters you expect the password to contain into an array. Write a stub function to test if your algorithm finds the correct password. Start with passwords of length 1, work your way up to 4 and see if your fake password is found on each iteration.
you can use the following code for getting random string. It will return you a string of 32 chars. you can get string of desired length by using substring(). Like if you want a string with 10 chars then:
import java.security.SecureRandom;
import java.math.BigInteger;
SecureRandom srandom = new SecureRandom();
String rand = new BigInteger(176, srandom).toString(32);
rand.substring(0,7);
Example int i=185;
Then I want to get that 'i' contains 3 digits and those digits are 1,8, and 5.
Hint: You need to take the modulus of the number by 10, to get the last digit. And then divide the same number by 10, do get the first two numbers. Repeat yourself as many times as required.
1st solution:
/**
* Using Integer/String classes functionality
*/
public class Shweta {
private static Integer i = 185;
public static void main(String... args) {
String iStr = i.toString();
for (char digit : iStr.toCharArray()) {
System.out.println(digit);
}
System.out.println("Length is: " + iStr.length());
}
}
2nd solution:
/**
* Doing that in a 'homework' way
*/
public class ShwetaNoCheats {
private static Integer i = 185;
public static void main(String... args) {
int length = 0;
while (i != 0) {
System.out.println(i - (i / 10) * 10);
i /= 10;
length++;
}
System.out.println("Length is: " + length);
}
}
The easy way to do this is by converting to a locale-agnostic string, then looking at each character in the string. I am not giving the final solution in case this is homework, but here are some important APIs...
Converting to string:
String stringForm = Integer.toString(number);
Handling negatives:
int nonNegative = Math.abs(number);
Length of a string:
int length = stringForm.length();
Getting the i-th character of a string:
char c = stringForm.charAt(i);
One way would be:
int i = 185;
int a = i / 100; // 1
int b = (i % 100) / 10; // 8
int c = i % 10; // 5
But i think you need something more generic? Try via string
int i = 185;
String iAsString = String.format("%d", i);
if(iAsString.contains("1")){
// do something...
}
And more advanced:
int i = 185;
String iAsString = String.format("%d", i);
HashSet<Integer> set = new HashSet<Integer>();
for(char c : iAsString.toCharArray()){
set.add(Integer.valueOf(String.valueOf(c)));
}
Then you can work on the set.
The number of decimal digits is also given by Math.ceil(Math.log10(i)), for integral i.
I have some random string with unknown content, what is known is that the content is alphanumeric and in lower case.
I am looking for a simple method to upper case a random number of the alpha characters in that string. The higher the randomness the better.
I can think of a few ways to do this, but none of them seem very optimal.
alright first solution:
public String randomizeCase(String myString){
Random rand = new Random();
StringBuilder build = new StringBuilder();
for(char c: myString.toCharArray()){
String s = new String(c);
if(Character.isLetter(c) && rand.nextBoolean()){
s = s.toUpperCase();
}
build.append(s);
}
return build.toString();
}
I dont like this solution because:
50% chance that every char is uppercased does not equal 50% chance that 50% of the chars are uppercased
There is a chance that nothing is upped cased
char to string conversion is ugly
The solution depends on the probabilistic model you choose. If for example you decide on binomial distribution, then you can traverse the chars, and switch every char to uppercase with a fixed probability p. The expected number of uppercase letters will be p * str.length():
public static String randomUpper(String str, double p) {
StringBuilder sb = new StringBuilder(str.length());
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
if (Character.isLetter(c) && Math.random() < p)
c = Character.toUpperCase(c);
sb.append(c);
}
return sb.toString();
}
If on the other hand you want to decide on the exact number of upercase letters for a given string, then the problem becomes a random sample problem (i.e. choose M positions to switch out of N positions in the string). This can be much faster than the first approach, when M is much smaller than N (though with Java's immutable strings the difference becomes minor because you have to copy the whole string anyway).
-- edit --
Now that you clarified the requirements, consider the following:
public static String randomUpper2(String str, double p) {
int letters = 0;
for (int i = 0; i < str.length(); i++) {
if (Character.isLetter(str.charAt(i)))
letters++;
}
int toChoose = (int) (p * letters);
StringBuilder sb = new StringBuilder(str.length());
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
if (Character.isLetter(c)) {
if (Math.random() < (toChoose/(double)letters)) {
c = Character.toUpperCase(c);
toChoose--;
}
letters--;
}
sb.append(c);
}
return sb.toString();
}
This code performs a random sample "on the fly", considering only alpha chars, as required. Use p=0.5 to switch exactly half of the letters.
Here is the code snippet for random sample problem (thanks Eyal for naming it). Not sure if that is what you are looking for.
Be aware, that this solution would run into an infinete loop if not enough lowercase letters are in the string. So you would need to tackle that as well, but I guess it is a starting point. ;-)
String myString = "9aie3ra3nr23rr5r21t";
System.out.println(upperCaseRandom(myString, 10));
public static String upperCaseRandom(String input, int n) {
StringBuilder output = new StringBuilder(input);
Random r = new Random();
for (int i = 0; i < n; i++) {
// Pick a place
int position = r.nextInt(input.length());
// Check if lowercase alpha
if (Character.isLowerCase(output.charAt(position))) {
output.setCharAt(position, Character.toUpperCase(output.charAt(position)));
} else {
i--;
}
}
return output.toString();
}
Edit:
Here is an improved version. It does change exactly n lowercase letters into uppercase letters (if there are enough, otherwise it changes all of them). The programm does not run into infinite loops, but still running time is a problem though.
public static String upperCaseRandom(String input, int n) {
final int length = input.length();
final StringBuilder output = new StringBuilder(input);
final boolean[] alreadyChecked = new boolean[length];
final Random r = new Random();
for (int i = 0, checks = 0; i < n && checks < length; i++) {
// Pick a place
int position = r.nextInt(length);
// Check if lowercase alpha
if (!alreadyChecked[position]) {
if (Character.isLowerCase(output.charAt(position))) {
output.setCharAt(position, Character.toUpperCase(output.charAt(position)));
} else {
i--;
}
checks++;
alreadyChecked[position] = true;
} else {
i--;
}
}
return output.toString();
}
I tried with
String lowerCasedRandomString = "4210281f-76ac-96b5-ed54-5458abf788d0";
String upperCasedRandomString = "4210281F-76AC-96B5-ED54-5458ABF788D0";
System.out.println(lowerCasedRandomString.toUpperCase());
System.out.println(upperCasedRandomString.toLowerCase());
I got the output
4210281F-76AC-96B5-ED54-5458ABF788D0
4210281f-76ac-96b5-ed54-5458abf788d0