I have a bit of a problem I have for example a word treasure
I am trying to find all the possible variants of this word possible only including letters and numbers a-z
0-9
that still look similar to the original word.
For example a couple of examples would be 7r345ur3
or 7rea5ure
. I need all the possible outcomes I spent a very long time looking for the definitions of the terms, I found the term Leet
which refers to replacing letters and numbers " L33t 5p34k "
The generators I found online are good at giving me 1 result but I need thousands.
I found this post ; Algorithm to generate all variants of a word
Which gave this JAVA code example in one of the answers;
static Map<Character, char[]> variants = new HashMap<Character, char[]>() {{
put('a', new char[] {'ä', 'à'});
put('b', new char[] { });
put('c', new char[] { 'ç' });
}};
public static Set<String> variation(String str) {
Set<String> result = new HashSet<String>();
if (str.isEmpty()) {
result.add("");
return result;
}
char c = str.charAt(0);
for (String tailVariant : variation(str.substring(1))) {
result.add(c + tailVariant);
for (char variant : variants.get(c))
result.add(variant + tailVariant);
}
return result;
}
Would this code example achieve what I'm trying to accomplish ?
I have never touched JAVA but from the looks of it I can add and edit these lines;
put('a', new char[] {'ä', 'à'});
put('b', new char[] { });
put('c', new char[] { 'ç' });
with all the possible characters I want to use but would someone be kind enough to change this so that it applies this to the input word of Treasure.
I really hope what I'm trying to achieve is clear in the question.
The method you found is a so-called recursive method, a method that constantly calls itself until a certain condition is met. If you want to simply adapt it and use it for your purposes, just change the map so that each letter is assigned the corresponding digit if such a digit exists that can be used as a substitute for the letter. Otherwise leave the array empty. i.e.
put('a',new char[] {'4'});
put('b',new char[] {'8'});
put('c',new char[] {});
put('d',new char[] {});
put('e',new char[] {'3'});
put('f',new char[] {});
put('g',new char[] {'6'});
put('h',new char[] {'4'});
put('i',new char[] {'1'});
put('j',new char[] {});
put('k',new char[] {});
put('l',new char[] {'1'}");
....
put('y',new char[] {'9'});
put('z',new char[] {'2'});
This should give you the desired result. But it would be better if you also understand what is going on inside the method. Recursive methods can be hard to read and it is not obvious at first sight what is going on. You can try to implement the method iteratively.
If you are a java newbie and can't implement the algorithm to create all combinations yourself, you might want to use a library. Generex for example would be good fit for your task. Generex takes a regular expression and can return a random string matched to the expression or all possible strings matching the regular expression. A simple example to show the use of the library:
import com.mifmif.common.regex.Generex;
public class Example {
public static void main(String[] args) {
Generex gen = new Generex("[t7][r2][e3][a4][s5][u][r2][e3]");
gen.getAllMatchedStrings().forEach(System.out::println);
}
}
Output:
72345u23
72345u2e
72345ur3
72345ure
7234su23
7234su2e
7234sur3
7234sure
723a5u23
....
trea5ure
treasu23
treasu2e
treasur3
treasure
In the above example generex will create strings by taking one letter or digit from each charachter class (i.e. from each square bracket) and return a list of all possible combinations.
You can generalize the above to use any input instead of a fixed string like treasure
in the above example. To do so, you need to create a map with each letter as key and the letter and possible substitution digits as value. Afterwards you just need to split your input at each char get the values for each letter from your map and pass those to generex. Something like below should get you started.
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import com.mifmif.common.regex.Generex;
public class Example {
private static final Map<String, String> MY_MAP = createMap();
public static void main(String[] args) {
String myString = "Lewis";
String random = randomVariant(myString);
System.out.println(random);
System.out.println();
List<String> variants = allVariants(myString);
variants.forEach(System.out::println);
}
private static Map<String, String> createMap() {
Map<String, String> result = new HashMap<>();
result.put("a","[a4]");
result.put("b","[b8]");
result.put("c","[c]");
result.put("d","[d]");
result.put("e","[e3]");
result.put("f","[f]");
result.put("g","[g6]");
result.put("h","[h4]");
result.put("i","[i1]");
result.put("j","[j]");
result.put("k","[k]");
result.put("l","[l1]");
result.put("m","[m]");
result.put("n","[n2]");
result.put("o","[o0]");
result.put("p","[p]");
result.put("q","[q]");
result.put("r","[r2]");
result.put("s","[s5]");
result.put("t","[t7]");
result.put("u","[u]");
result.put("v","[v]");
result.put("w","[w]");
result.put("x","[x]");
result.put("y","[y9]");
result.put("z","[z2]");
return Collections.unmodifiableMap(result);
}
public static List<String> allVariants(String str){
String reg = Pattern.compile("").splitAsStream(str.toLowerCase()).map(MY_MAP::get).collect(Collectors.joining());
Generex gen = new Generex(reg);
return gen.getAllMatchedStrings();
}
public static String randomVariant(String str){
String reg = Pattern.compile("").splitAsStream(str.toLowerCase()).map(MY_MAP::get).collect(Collectors.joining());
Generex gen = new Generex(reg);
return gen.random();
}
}
output:
13wi5
13w15
13w1s
13wi5
13wis
1ew15
1ew1s
1ewi5
1ewis
l3w15
l3w1s
l3wi5
l3wis
lew15
lew1s
lewi5
lewis