me gustaría hacer esto mediante la construcción del mínimo Deterministic Finite Automaton para el idioma.Si está empezando con una expresión regular, esto se puede hacer automáticamente mediante la construcción de Thompson seguida de la construcción del subconjunto y la minimización. Ver this description por ejemplo.
Con un DFA en la mano, se puede usar algo como esto algoritmo:
Let P = { < START, [""] > } be a set of pairs <State, list of strings>
for n = 0, 1, ... Max
Let P' = {} be a new set
while P is not empty
Remove the pair <s, L> from P
For each transition s -- c --> t in alpha order of c
if t is an accepting state,
output l + c for each string l in L
put <t, L + c> in P' (** i.e. append c to each string in L)
end
Set P = P'
end
Tenga en cuenta que el paso marcado **
necesidades para ser verdad inserción del equipo, como duplicados pueden surgir fácilmente.
Este es un algoritmo central. P
puede crecer exponencialmente con la longitud de salida, pero este es solo el precio de rastrear todas las posibilidades para una cadena de salida futura. Las restricciones de orden/tamaño/espacio que mencionó pueden garantizarse manteniendo el orden ordenado en las listas L
y cortando la búsqueda cuando se alcanzan los límites de recursos.
Editar
Aquí está un ejemplo de Java juguete donde he duro codificado para la DFA simples literales de punto flotante binario con signo menos opcional. Esto utiliza un esquema ligeramente diferente al pseudocódigo anterior para obtener un orden de salida ordenado estricto y acomodar rangos de caracteres.
import java.util.Comparator;
import java.util.TreeSet;
public class Test{
public static class DFA {
public static class Transition {
final int to;
final char lo, hi; // Character range.
public Transition(int to, char lo, char hi) {
this.to = to;
this.lo = lo;
this.hi = hi;
}
public Transition(int to, char ch) {
this(to, ch, ch);
}
}
// transitions[i] is a vector of transitions from state i.
final Transition [] [] transitions;
// accepting[i] is true iff state i is accepting
final boolean [] accepting;
// Make a fresh immutable DFA.
public DFA(Transition [] [] transitions, boolean [] accepting) {
this.transitions = transitions;
this.accepting = accepting;
}
// A pair is a DFA state number and the input string read to get there.
private static class Pair {
final int at;
final String s;
Pair(int at, String s) {
this.at = at;
this.s = s;
}
}
// Compare pairs ignoring `at` states, since
// they are equal iff the strings are equal.
private Comparator<Pair> emitOrder = new Comparator<Pair>() {
@Override
public int compare(Pair a, Pair b) {
return a.s.compareTo(b.s);
}
};
// Emit all strings accepted by the DFA of given max length.
// Output is in sorted order.
void emit(int maxLength) {
TreeSet<Pair> pairs = new TreeSet<Pair>(emitOrder);
pairs.add(new Pair(0, ""));
for (int len = 0; len <= maxLength; ++len) {
TreeSet<Pair> newPairs = new TreeSet<Pair>(emitOrder);
while (!pairs.isEmpty()) {
Pair pair = pairs.pollFirst();
for (Transition x : transitions[pair.at]) {
for (char ch = x.lo; ch <= x.hi; ch++) {
String s = pair.s + ch;
if (newPairs.add(new Pair(x.to, s)) && accepting[x.to]) {
System.out.println(s);
}
}
}
}
pairs = newPairs;
}
}
}
// Emit with a little DFA for floating point numbers.
public void run() {
DFA.Transition [] [] transitions = {
{ // From 0
new DFA.Transition(1, '-'),
new DFA.Transition(2, '.'),
new DFA.Transition(3, '0', '1'),
},
{ // From 1
new DFA.Transition(2, '.'),
new DFA.Transition(3, '0', '1'),
},
{ // From 2
new DFA.Transition(4, '0', '1'),
},
{ // From 3
new DFA.Transition(3, '0', '1'),
new DFA.Transition(4, '.'),
},
{ // From 4
new DFA.Transition(4, '0', '1'),
}
};
boolean [] accepting = { false, false, false, true, true };
new DFA(transitions, accepting).emit(4);
}
public static void main (String [] args) {
new Test().run();
}
}
No estoy íntimamente familiarizado con Delphi, solo puedo hablar desde un punto de vista general. En mi opinión, la mejor manera de hacer esto sería analizar una expresión regular en un gráfico que represente su máquina de estado equivalente (wikipedia debería ser capaz de apuntar en la dirección correcta). A partir de ahí, se pueden generar palabras realizando un recorrido en profundidad de dicho gráfico (teniendo en cuenta que es muy probable que sea cíclico, por supuesto). La desventaja aquí es que no podemos aprovechar un idioma integrado en el soporte de expresiones regulares. – jpm
+1: Muy interesante. Es un enfoque verdaderamente generativo como opuesto a mi altamente ineficiente forma generador/probador. En mi opinión, no hay inconveniente alguno: el soporte de expresiones regulares incorporado es para la evaluación y me engaña al idear una solución. Puede considerar migrar su comentario como respuesta, lo encuentro aceptable. Gracias. – menjaraz
Esto parece una manera tonta de usar expresiones regulares. Creo que un sistema de expresión de generador simplificado que genere un generador-objeto, que podría ser algo similar a algunas características de expresiones regulares (admitir '[AZ] .' y' [AZ] * 'solo (a un límite fijo), sería suficiente. –