Is there anything in java that does the opposite of regular expressions?
My task is: given a defined total length for a string and each position can only consist of predefined specific characters, generate all possible strings.
To give an example: I want to create all stings of length 3 where the positions are defined as
[ABC][123][XYZ]
This means that the first position can only be A, B or C
, the second position one of the numbers 1 to 3
and so on. Valid strings would therefore be
A1X
A1Y
A1Z
A2X
A2Y
A2Z
...
...
C3Z
For the length three I can of course use a nested loop. My problem is I don't know in advance how long the string has to be or how many valid characters each position has. Any ideas?
Code for length 3 and each position 3 possible chars:
public static void main(String[] args) {
String[] first = {"A", "B", "C"};
String[] second = {"1", "2", "3"};
String[] third = {"X", "Y", "Z"};
List<String> result = createStrings(first, second, third);
result.forEach(System.out::println);
}
static List<String> createStrings(String[] ... strs) {
String[] first = strs[0];
String[] second = strs[1];
String[] third = strs[2];
List<String> result = new ArrayList<>();
for (int i = 0; i < first.length; i++) {
for (int j = 0; j < second.length; j++) {
for (int k = 0; k < third.length; k++) {
result.add(first[i] + second[j] + third[k]);
}
}
}
return result;
}
I need something flexible, which works for all inputs. Or a way to dynamically create a nested loop depending on strs.length
which defines how many loops I need.
You can use recursion:
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
String[] first = { "A", "B", "C" };
String[] second = { "1", "2", "3" };
String[] third = { "X", "Y", "Z" };
String[] fourth = { "K", "L", "M" };
String[] fifth = { "7", "8", "9" };
List<String> result = createStrings(first, second, third, fourth, fifth);
result.forEach(System.out::println);
}
static List<String> createStrings(String[]... strs) {
List<String> res = new ArrayList<>();
getStrings(0, "", res, strs);
return res;
}
static void getStrings(int level, String curr, List<String> res, String[]... strs) {
if (level == strs.length) {
res.add(curr);
return;
}
for (String ch : strs[level]) {
getStrings(level + 1, curr + ch, res, strs);
}
}
}
A1XK7
A1XK8
A1XK9
A1XL7
A1XL8
A1XL9
A1XM7
...
C3ZK9
C3ZL7
C3ZL8
C3ZL9
C3ZM7
C3ZM8
C3ZM9
""
/ | \
A B C
/|\ /|\ /|\
1 2 3 1 2 3 1 2 3
/|\ /|\ /|\ /|\ /|\
X Y Z X Y Z X Y Z X Y Z
/|\/|\/|\/|\/|\/|\/|\/|\
K L M K L M K L M K L M K L M
/|\/|\/|\/|\/|\/|\/|\/|\/|\/|\
... ... ... ... ... ... ... ...
In this example, we have five levels. We want to generate all possible combinations of characters by recursively concatenating each character (from each level) using the current array (strs[level]
) and then move to the next level.
Initially, we call createStrings()
with all five arrays, which calls getStrings(0, "", res, strs)
.
Here are the recursion stacks:
...
Let's trace one path through the recursion stack:
getStrings(0, "", res, strs)
, calls getStrings(1, "A", res, strs)
;getStrings(1, "A", res, strs)
, calls getStrings(2, "A1", res, strs)
;getStrings(2, "A1", res, strs)
, calls getStrings(3, "A1X", res, strs)
;getStrings(3, "A1X", res, strs)
, calls getStrings(4, "A1XK", res, strs)
;getStrings(4, "A1XK", res, strs)
, calls getStrings(5, "A1XK7", res, strs)
; andgetStrings(5, "A1XK7", res, strs)
, adds "A1XK7" to the res
.