/* package whatever; // don't place package name! */
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
class Word {
public static void main
(String[] args
) { Symbol sa = new Symbol("a");
Symbol sb = new Symbol("b");
Symbol sc = new Symbol("c");
Symbol sd = new Symbol("d");
Symbol se = new Symbol("e");
Symbol s1 = new Symbol("1");
Symbol s2 = new Symbol("2");
Symbol s3 = new Symbol("3");
Symbol s4 = new Symbol("4");
Symbol sat = new Symbol("@");
Symbol sdot = new Symbol(".");
Symbol[] chars = {sa, sb, sc, sd, se, s1, s2, s3, s4};
Symbol[][][] tests = {
{
chars,
},
{
chars,
chars,
chars,
{sat},
chars,
chars,
chars,
{sdot},
chars,
chars,
chars,
}
};
Word[] testcases = new Word[tests.length];
int pos = 0;
for (Symbol[][] syms : tests) {
List<Symbol> word = new ArrayList<>();
for (Symbol[] choices : syms) {
List<SymbolChoice> opts = new ArrayList<>();
for (Symbol c : choices) {
opts.add(new SymbolChoice(c));
}
word.add(new Symbol(choices[0].value, opts));
}
testcases[pos++] = new Word(word);
}
long[] warmups = new long[10000];
long max
= Long.
MIN_VALUE; long min
= Long.
MAX_VALUE; long sum = 0;
for (int i = 0; i < warmups.length; i++) {
long start
= System.
nanoTime(); testcases[0].forceFitRegex("a", false);
warmups
[i
] = System.
nanoTime() - start
; min = warmups[i] < min ? warmups[i] : min;
max = warmups[i] > max ? warmups[i] : max;
sum += warmups[i];
}
System.
out.
printf("Warmups %d max %d min %d avg %.2f%n", warmups.
length, max, min, sum
/ (double)warmups.
length);
for (Word torun : testcases) {
long time
= System.
nanoTime(); List<List<SymbolChoice>> result = torun.forceFitRegex("[bcd]+@[a-z]+\\.[a-z]+", true);
time
= System.
nanoTime() - time
; System.
out.
printf("Result %d in %.3fms%n", result.
size(), time
/ 1000000.0);
}
}
private static class Symbol {
private final List<SymbolChoice> choices;
this.value = value;
this.choices = null;
}
public Symbol
(String value, List
<SymbolChoice
> choices
) { this.value = value;
this.choices = choices;
}
public List<SymbolChoice> getSymbolChoices() {
return choices;
}
@Override
return value;
}
}
private static class SymbolChoice {
private final Symbol symbol;
public SymbolChoice(Symbol symbol) {
this.symbol = symbol;
}
@Override
return "C:" + symbol;
}
}
private final List<Symbol> syms;
public Word(List<Symbol> syms) {
super();
this.syms = syms;
}
private List<Symbol> getSymbols() {
return syms;
}
public List
<List
<SymbolChoice
>> forceFitRegex
(final String regex
) { return forceFitRegex(regex, false);
}
public List
<List
<SymbolChoice
>> forceFitRegex
(final String regex,
boolean debug
) { Objects.requireNonNull(regex, "regex");
final List<Symbol> symbols = getSymbols();
SymbolChoice[][] options = new SymbolChoice[symbols.size()][];
int pos = 0;
int combinations = 1;
final SymbolChoice[] emptyChoice = new SymbolChoice[0];
for (Symbol symbol : getSymbols()) {
options[pos] = symbol.getSymbolChoices().toArray(emptyChoice);
combinations *= options[pos].length;
pos++;
}
Pattern pattern = Pattern.compile(regex);
int[] stack = new int[options.length];
int[] sbsize = new int[options.length + 1];
List<List<SymbolChoice>> listOfSymbolChoices = new ArrayList<List<SymbolChoice>>();
StringBuilder sb = new StringBuilder(stack.length);
int depth = 0;
int testcnt = 0;
while (depth >= 0) {
if (stack[depth] >= options[depth].length) {
stack[depth] = 0;
depth--;
if (depth >= 0) {
sb.setLength(sbsize[depth]);
stack[depth]++;
}
} else {
sb.append(options[depth][stack[depth]].symbol.value);
Matcher matcher = pattern.matcher(sb);
testcnt++;
boolean found = matcher.matches();
if (depth == options.length - 1) {
if (found) {
// we have a viable answer here, we can report it....
List<SymbolChoice> match = new ArrayList<>(stack.length);
for (int i = 0; i < stack.length; i++) {
match.add(options[i][stack[i]]);
}
listOfSymbolChoices.add(match);
}
sb.setLength(sbsize[depth]);
stack[depth]++;
} else if (found || matcher.hitEnd()) {
// we have a viable answer here, we can descend....
depth++;
sbsize[depth] = sb.length();
} else {
// nothing viable down here....
sb.setLength(sbsize[depth]);
stack[depth]++;
}
}
}
if (debug) {
System.
out.
println("Combinations: " + combinations
+ " actual tests " + testcnt
); }
return listOfSymbolChoices;
}
}