自定义规则解析器

时间:2011-03-09 03:27:16

标签: javascript parsing

我有一套面具

面具看起来像这样

  

09 {2,9-} n的(6)'
  //读为09
  // [2到9之间的数字]
  // [随机数] [重复表达6次]

     

'029n(7,10)'
  //读作029
  // [随机数] [重复7到10次之间的表达]

     

'029n(2,5){8,15}(7,10)N'
  //读作029
  // [随机数] [重复2到5次之间的表达]
  // [8到15之间的随机数] [重复7到10次之间的表达]
  // [随机数]

     

作为一个例子,探险3可以解决为什么   '029n(4){4,9}(7)N'
  “029nnnn {4,9} {4,9} {4,9} {4,9} {4,9} {4,9} {4,9} n的
  “029nnnn {5} {9} {4} {8} {5} {9} {9} n的
  '029nnnn5948599n'
  '029023559485999'

我需要在javascript中编写一个解析器,它可以根据这些规则生成一个字符串。 请注意,这是 not validation ,它是字符串生成。

最好的办法是什么?

1 个答案:

答案 0 :(得分:3)

尝试自定义解析器。用作,

var generator = new PatternGenerator('09{2,9}n(6)');
generator.generate(); // 096555555
generator.generate(); // 095000000

结帐example

构造函数,

function PatternGenerator(pattern) {
    var tokens = null;

    this.generate = function() {
        var stack = [];
        tokens = pattern.split('');

        // Read each token and add
        while (tokens.length) {
            var token = lookahead();
            if (isDigit(token)) {
                stack.push(consumeNumber());
            }
            else if (token == "n") {
                stack.push(consumeVariableNumber());
            }
            else if (token == "(") {
                var topObject = stack.pop();
                stack.push(consumeRepetition(topObject));
            }
            else if (token == "{") {
                stack.push(consumeVariableRangeNumber());
            }
            else {
                throw new Error("Invalid input");
            }
        }
        return stack.join('');
    }

    // [0-9]+
    function consumeNumber() {
        var number = "";
        while (isDigit(lookahead())) {
            number += consume();
        }
        return number;
    }

    // "n"
    function VariableNumber() {
        var number = generateRandomNumber();

        this.toString = function() {
            return Number(number);
        };
    }

    function consumeVariableNumber() {
        consume();
        return new VariableNumber();
    }

    // {x, y}
    function VariableRangeNumber(start, end) {
        var number = generateRandomNumberBetween(start, end);

        this.toString = function() {
            return Number(number);
        };
    }

    function consumeVariableRangeNumber() {
        consume(); // {
        var firstNumber = consumeNumber();
        consume(); // ,
        var secondNumber = consumeNumber();
        consume(); // }
        return new VariableRangeNumber(firstNumber, secondNumber);
    }

    // <expression>(x)
    function Repeat(object, times) {
        this.toString = function() {
            var string = "";
            for (var i = 0; i < times; i++) {
                string += object;
            }
            return string;
        };
    }

    // <expression>(x, y)
    function RepeatWithRange(object, start, end) {
        var times = generateRandomNumberBetween(start, end);

        this.toString = function() {
            return new Repeat(object, times).toString();
        };
    }

    function consumeRepetition(object) {
        consume(); // (
        var firstNumber, secondNumber;
        var firstNumber = consumeNumber();
        if (lookahead() == ",") {
            consume(); // ,
            secondNumber = consumeNumber();
        }
        consume(); // )

        if (typeof secondNumber == 'undefined') {
            return new Repeat(objectToRepeat, firstNumber);
        }
        else {
            return new RepeatWithRange(object, firstNumber, secondNumber);
        }
    }

    // Helpers to generate random integers
    function generateRandomNumber() {
        var MAX = Math.pow(2, 52);
        return generateRandomNumberBetween(0, MAX);
    }

    function generateRandomNumberBetween(min, max) {
        return Math.floor(Math.random() * (max - min + 1)) + min;
    }

    function lookahead() {
        return tokens[0];
    }

    function consume() {
        return tokens.shift();
    }

    function isDigit(character) {
        return /\d/.test(character);
    }
}