Я пытаюсь временно invRegex.py в реализацию node.js, но я все еще боюсь с этим. У меня уже есть дерево разбора регулярных выражений благодаря ret.js tokenizer, и он работает очень хорошо, но фактическое поколение и конкатенация всех отличные элементы, способные эффективно использовать память, очень бросают мне вызов. Чтобы это было просто, скажем, у меня есть следующее регулярное выражение:
[01]{1,2}@[a-f]
При подаче на invRegex.py
выводится следующий результат (tabbified для меньшего пространства):
[email protected] [email protected] [email protected] [email protected] [email protected] [email protected]
[email protected] [email protected] [email protected] [email protected] [email protected] [email protected]
[email protected] [email protected] [email protected] [email protected] [email protected] [email protected]
[email protected] [email protected] [email protected] [email protected] [email protected] [email protected]
[email protected] [email protected] [email protected] [email protected] [email protected] [email protected]
[email protected] [email protected] [email protected] [email protected] [email protected] [email protected]
Учитывая, что я могу получить каждый отдельный токен и создать массив всех допустимых отдельных выходов:
[01]{1,2} = function () {
return ['0', '00', '01', '1', '10', '11'];
};
@ = function () {
return ['@'];
};
[a-f] = function () {
return ['a', 'b', 'c', 'd', 'e', 'f'];
};
Я могу вычислить декартовой продукт всех массивов и получить тот же ожидаемый результат:
var _ = require('underscore');
function cartesianProductOf() {
return _.reduce(arguments, function(a, b) {
return _.flatten(_.map(a, function(x) {
return _.map(b, function(y) {
return x.concat([y]);
});
}), true);
}, [ [] ]);
};
var tokens = [
['0', '00', '01', '1', '10', '11'],
['@'],
['a', 'b', 'c', 'd', 'e', 'f'],
];
var result = cartesianProductOf(tokens[0], tokens[1], tokens[2]);
_.each(result, function (value, key) {
console.log(value.join(''));
});
Проблема заключается в том, что он содержит все 36 значений в памяти, если у меня было несколько более сложное регулярное выражение, например [a-z]{0,10}
, оно хранило бы значения 146813779479511
в памяти, что совершенно невозможно. Я хотел бы обработать этот огромный список асинхронным способом, передавая каждую сгенерированную комбинацию в обратный вызов и позволяя мне прерывать процесс в любой разумной точке, которую я считаю подходящей, подобно invRegex.py или этот пакет Haskell - к сожалению, я не могу понять Haskell, и я не знаю, как имитировать поведение генератора в Python для Javascript.
Я попробовал запустить несколько простых экспериментов генератора в node 0.11.9 (с --harmony
), как этот:
function* alpha() {
yield 'a'; yield 'b'; yield 'c';
}
function* numeric() {
yield '0'; yield '1';
}
function* alphanumeric() {
yield* alpha() + numeric(); // what the diff between yield and yield*?
}
for (var i of alphanumeric()) {
console.log(i);
}
Излишне говорить, что вышесказанное не работает. =/
Прижав голову к стене здесь, так что любая помощь в решении этой проблемы будет высоко оценена.
UPDATE. Вот пример дерева синтаксического анализа ret.js для b[a-z]{3}
:
{
"type": ret.types.ROOT,
"stack": [
{
"type": ret.types.CHAR,
"value": 98 // b
},
{
"type": ret.types.REPETITION,
"max": 3,
"min": 3,
"value": {
"type": ret.types.SET,
"not": false,
"set": [
{
"type": ret.types.RANGE,
"from": 97, // a
"to": 122 // z
}
]
}
}
]
]
}
Тип SET
/RANGE
должен давать 26 различных значений, а родительский тип REPETITION
должен принимать это предыдущее значение в степени 3, получая 17576 различных комбинаций. Если бы мне пришлось сгенерировать сплющенный массив tokens
, как и раньше, для cartesianProductOf
, промежуточные сплющенные значения занимали бы столько же места, сколько и собственно декартово произведение.
Надеюсь, что этот пример лучше объясняет проблему, с которой я столкнулся.