这是什么语法?

时间:2011-08-12 12:24:51

标签: parsing grammar

我必须解析一个包含变量值对组的文档,这些变量值对被序列化为一个字符串,例如像这样:

4^26^VAR1^6^VALUE1^VAR2^4^VAL2^^1^14^VAR1^6^VALUE1^^

以下是不同的元素:

  1. 组ID:

    4 ^ 26 ^ VAR1 ^ 6 ^ VALUE1 ^ VAR2 ^ 4 ^ VAL2 ^^的 1 ^ 14 ^ VAR1 ^ 6 ^ VALUE1 ^^

    < / LI>
  2. 每组的字符串表示长度:

    4 ^的 26 ^ VAR1 ^ 6 ^ VALUE1 ^ VAR2 ^ 4 ^ VAL2 ^^ 1 ^的 14 ^ VAR1 ^ 6 ^ VALUE1 ^^

    < / LI>
  3. 其中一个小组:

    4 ^ 26 ^ VAR1 ^ 6 ^ VALUE1 ^ VAR2 ^ 4 ^ VAL2 ^^ 1 ^ 14 ^ VAR1 ^ 6 ^ VALUE1 ^^

  4. 变量:

    4 ^ 26 ^的 VAR1 ^ 6 ^ VALUE1 ^的 VAR2 ^ 4 ^ VAL2 ^^ 1 ^ 14 ^的 VAR1 ^ 6 ^ VALUE1 ^^

  5. 值的字符串表示长度:

    4 ^ 26 ^ VAR1 ^的 6 ^ VALUE1 ^ VAR2 ^的 4 ^ VAL2 ^^ 1 ^ 14 ^ VAR1 ^的 6 ^ VALUE1 ^^

  6. 价值观本身:

    4 ^ 26 ^ VAR1 ^ 6 ^的 VALUE1 ^ VAR2 ^ 4 ^的 VAL2 ^^ 1 ^ 14 ^ VAR1 ^ 6 ^的 VALUE1 ^^

  7. 变量仅由字母数字字符组成。 没有对这些值进行假设,即它们可能包含任何字符,包括^

    这种语法有名字吗?是否有可以处理这个混乱的解析库?

    到目前为止,我正在使用自己的解析器,但由于我需要检测并处理损坏的序列化,因此代码看起来相当混乱,因此我对解析器库的问题可以解除负担。

2 个答案:

答案 0 :(得分:1)

最简单的方法是注意有两个嵌套级别以相同的方式工作。模式非常简单:

id^length^content^

在外层,这会产生一组组。在每个组中,content遵循完全相同的模式,只有id是变量名称,content是变量值。

因此,您只需要编写一次该逻辑,然后可以使用它来解析这两个级别。只需编写一个将字符串分解为id / content对列表的函数。调用它一次以获取组,然后循环遍历它们再次为每个content调用它以获取该组中的变量。

将它分解为这些步骤,首先我们需要一种从字符串中获取“标记”的方法。此函数返回一个具有三种方法的对象,以查明我们是否处于“文件结尾”,并获取下一个分隔或计数的子字符串:

var tokens = function(str) {
    var pos = 0;
    return {
        eof: function() {
            return pos == str.length;
        },
        delimited: function(d) {
            var end = str.indexOf(d, pos);
            if (end == -1) {
                throw new Error('Expected delimiter');
            }
            var result = str.substr(pos, end - pos);
            pos = end + d.length;
            return result;
        },
        counted: function(c) {
            var result = str.substr(pos, c);
            pos += c;
            return result;
        }
    };
};

现在我们可以方便地编写可重用的解析函数:

var parse = function(str) {
    var parts = {};
    var t = tokens(str);
    while (!t.eof()) {
        var id = t.delimited('^');
        var len = t.delimited('^');
        var content = t.counted(parseInt(len, 10));
        var end = t.counted(1);
        if (end !== '^') {
            throw new Error('Expected ^ after counted string, instead found: ' + end);
        }
        parts[id] = content;
    }
    return parts;
};

它构建一个对象,其中键是ID(或变量名)。我觉得它们的名字并不重要。

然后我们可以在两个级别使用它来创建完成整个工作的功能:

var parseGroups = function(str) {
   var groups = parse(str);
   Object.keys(groups).forEach(function(id) {
     groups[id] = parse(groups[id]);
   });
   return groups;
}

对于您的示例,它会生成此对象:

{
  '1': { 
    VAR1: 'VALUE1' 
  },
  '4': {
    VAR1: 'VALUE1',
    VAR2: 'VAL2'
  } 
}

答案 1 :(得分:0)

我不认为为此创建语法是一项微不足道的任务。但另一方面,简单直接的方法并不难。您知道每个关键字符串的相应字符串长度。所以你只需按照那些长度分开你的字符串..

你在哪里看到问题?