net.moznion.random.string.RandomStringGenerator Maven / Gradle / Ivy
package net.moznion.random.string;
import net.moznion.random.string.UserDefinedLetterPickerScanner.ScannedUserDefinedPicker;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.stream.Collectors;
/**
* Generator of random string.
*
*
* This class doesn't generate secure strings. So please use SecureRandom class if you want to use
* with such a purpose.
*
* @author moznion
*
*/
public class RandomStringGenerator {
private int numOfUpperLimit;
private final Map userDefinedPickers;
private final Random random;
private final RandomLetterPickers pickers;
private static final int DEFAULT_NUM_OF_UPPER_LIMIT = 10;
/**
* Instantiate generator with a default number of upper limit for regex quantifiers (for example
* {@code *}, {@code +} and etc; default value is 10) and a default instance of Random.
*/
public RandomStringGenerator() {
this(new Random(), DEFAULT_NUM_OF_UPPER_LIMIT);
}
/**
* Instantiate generator with a number of upper limit for regex quantifiers (for example {@code *}
* , {@code +} and etc) and a default instance of Random.
*
* @param numOfUpperLimit Number of upper limit for quantifiers
*/
public RandomStringGenerator(int numOfUpperLimit) {
this(new Random(), numOfUpperLimit);
}
/**
* Instantiate generator with a default number of upper limit for regex quantifiers (for example
* {@code *}, {@code +} and etc; default value is 10) and an instance of Random.
*
* @param random Instance of Random
*/
public RandomStringGenerator(Random random) {
this(random, DEFAULT_NUM_OF_UPPER_LIMIT);
}
/**
* Instantiate generator with a number of upper limit for regex quantifiers (for example {@code *}
* , {@code +} and etc) and an instance of Random.
*
* @param random Instance of Random
* @param numOfUpperLimit Number of upper limit for quantifiers
*/
public RandomStringGenerator(Random random, int numOfUpperLimit) {
this.numOfUpperLimit = numOfUpperLimit;
this.random = random;
this.userDefinedPickers = new HashMap<>();
this.pickers = new RandomLetterPickers(this.random);
}
/**
* Generate random string from pattern.
*
*
* You can use following characters as pattern.
*
* - {@code c} : Any Latin lower-case character
* - {@code C} : Any Latin upper-case character
* - {@code n} : Any digit {@code [0-9]}
* - {@code !} : A symbol character {@code [~`!@$%^&*()-_+= []|\:;"'.<>?/#,]}
* - {@code .} : Any of the above
* - {@code s} : A "salt" character {@code [A-Za-z0-9./]}
* - {@code b} : An ASCIII character which has code from 0 to 255
*
*
*
* e.g.
*
*
*
* RandomStringGenerator generator = new RandomStringGenerator();
*
* // generates random string (e.g. "aB4@X.Ç")
* String randomString = generator.generateFromPattern("cCn!.sb");
*
*
*
* @param pattern Pattern string
* @return Random string which is generated according to pattern
*/
public String generateFromPattern(final String pattern) {
return Arrays.stream(pattern.split("")).map(patternCharacter -> {
RandomLetterPicker picker;
switch (patternCharacter) {
case "c":
picker = pickers.getLowerCase();
break;
case "C":
picker = pickers.getUpperCase();
break;
case "n":
picker = pickers.getDigit();
break;
case "!":
picker = pickers.getSymbol();
break;
case ".":
picker = pickers.getAny();
break;
case "s":
picker = pickers.getSalt();
break;
case "b":
picker = pickers.getBinary();
break;
default:
throw new RuntimeException("Detected invalid pattern character: " + patternCharacter);
}
return picker.pickRandomLetter();
}).collect(Collectors.joining());
}
/**
* Generate random string from regular expression.
*
*
* You can use following meta characters as regex.
*
* - {@code \w} : Alphanumeric + "_" {@code [A-Za-z0-9_]}
* - {@code \d} : Digits {@code [0-9]}
* - {@code \W} : Printable characters other than those in \w
* - {@code \D} : Printable characters other than those in \d
* - {@code \s} : Whitespace characters {@code [ \t]}
* - {@code \S} : Printable characters
* - {@code .} : Printable characters
* - {@code []} : Character classes (Example of usage {@code [a-zA-Z]})
* {}
: Repetition
* - {@code *} : Same as {0,}
* - {@code ?} : Same as {0,1}
* - {@code +} : Same as {1,}
*
*
*
* e.g.
*
*
*
* RandomStringGenerator generator = new RandomStringGenerator();
*
* // generates random string (e.g. "a5B123 18X")
* String randomString = generator.generateByRegex("\\w+\\d*\\s[0-9]{0,3}X");
*
*
*
* @param regex Pattern based on regular expression
* @return Random String
*/
public String generateByRegex(final String regex) {
String expanded = new RegexNormalizer(numOfUpperLimit, random).normalizeQuantifiers(regex);
final String[] regexCharacters = expanded.split("");
final int length = regexCharacters.length;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < length; i++) {
String character = regexCharacters[i];
RandomLetterPicker picker = null;
String candidateCharacter = null;
switch (character) {
case "\\":
try {
character = regexCharacters[++i];
} catch (ArrayIndexOutOfBoundsException e) {
throw new RuntimeException("Detected invalid escape character");
}
switch (character) {
case "w":
picker = pickers.getWord();
break;
case "d":
picker = pickers.getDigit();
break;
case "W":
picker = pickers.getNotWord();
break;
case "D":
picker = pickers.getNotDigit();
break;
case "s":
picker = pickers.getSpace();
break;
case "S":
picker = pickers.getAny();
break;
default:
candidateCharacter = character;
}
break;
case "[":
try {
ScannedUserDefinedPicker scannedUserDefinedPicker =
UserDefinedLetterPickerScanner.scan(regexCharacters, i);
String key = scannedUserDefinedPicker.getKey();
i = scannedUserDefinedPicker.getCursor();
if (userDefinedPickers.get(key) == null) {
RandomLetterPicker userDefinedPicker = RandomLetterPicker
.constructByCharacterRange(scannedUserDefinedPicker.getBounds());
userDefinedPickers.put(key, userDefinedPicker);
}
picker = userDefinedPickers.get(key);
} catch (ArrayIndexOutOfBoundsException e) {
throw new RuntimeException("Occurs parsing error");
}
break;
case ".":
picker = pickers.getAny();
break;
default:
candidateCharacter = character;
}
int repetitionNum = 1;
if (i + 1 < length) {
String nextCharacter = regexCharacters[i + 1];
if (nextCharacter.equals("{")) {
int j = i + 1;
StringBuilder sbForQuantifier = new StringBuilder();
try {
while (!(nextCharacter = regexCharacters[++j]).equals("}")) {
sbForQuantifier.append(nextCharacter);
}
try {
repetitionNum = Integer.parseInt(sbForQuantifier.toString(), 10);
i = j;
} catch (RuntimeException e) {
// do nothing
}
} catch (ArrayIndexOutOfBoundsException e) {
// do nothing
}
}
}
if (picker != null) {
for (int j = 0; j < repetitionNum; j++) {
sb.append(picker.pickRandomLetter());
}
} else if (candidateCharacter != null) {
for (int j = 0; j < repetitionNum; j++) {
sb.append(candidateCharacter);
}
} else {
throw new RuntimeException("Occurs parsing error");
}
}
return sb.toString();
}
/**
* Get number of upper limit for regex quantifiers, for example {@code *}, {@code +} and etc.
*
* @return Number of upper limit for quantifiers
*/
public int getNumOfUpperLimit() {
return numOfUpperLimit;
}
/**
* Set number of upper limit for regex quantifiers, for example {@code *}, {@code +} and etc.
*
* @param numOfUpperLimit Number of upper limit for quantifiers
*/
public void setNumOfUpperLimit(int numOfUpperLimit) {
this.numOfUpperLimit = numOfUpperLimit;
}
}