0

我得到一个传递的字符串,它是一个独特的格式(虽然是一致的),我需要能够解析它,以便我可以修改它的各个部分,然后将它放回一起并将其作为字符串传回。

这是我通过的字符串。它的内容会定期更改,但每个项目的结构将保持不变。

    View
{
    Name: View1;
    Image
    {
        BackgroundImage: Image.gif;
        Position: 0, 0;
        Width: 320;
        Height: 480;
    }

    Button
    {
        BackgroundImage: Button.gif;
        Transition: View2;
        Position: 49, 80;
        Width: 216;
        Height: 71;
    }

    Button
    {
        BackgroundImage: Button2.gif;
        Position: 65, 217;
        Width: 188;
        Height: 134;
    }

    Label
    {
        Position: 106, 91;
        Width: 96;
        Height: 34;
        Text: "Button";
        FontSize: 32;
        Color: 0.12549, 0.298039, 0.364706, 1;
    }
    Scroll
    {
        Position: 106, 91;
        Width: 96;
        Height: 34;
        Button{
            BackgroundImage: Button2.gif;
            Position: 65, 217;
            Width: 188;
            Height: 134;
        }
        Button{
            BackgroundImage: Button2.gif;
            Position: 65, 217;
            Width: 188;
            Height: 134;
        }

    }

}

我想我需要一个递归函数来查找每个 k,v 并将其放入适当的 Object 或 JSON 文件中,以便我可以修改。我所能得到的最远的是能够解析单个级别并将其放入 k,v 对象中。这是它解析的代码和字符串。

修改字符串以使用我的代码(单级深度。我删除了 View{} 和 Scroll{}):

var content='Image{BackgroundImage: Image.gif;Position: 0, 0;Width: 320;Height: 480;}Image{BackgroundImage: Image2.gif;Position: 0, 0;Width: 320;Height: 480;}Button{BackgroundImage: Button.gif;Position: 49, 80;Width: 216;Height: 71;}Button{BackgroundImage: Button.gif;Position: 49, 80;Width: 216;Height: 71;}Button{BackgroundImage: Button2.gif;Transition: View2;Position: 65, 217;Width: 188;Height: 134;}Button{BackgroundImage: Button3.gif;Transition: View2;Position: 65, 217;Width: 188;Height: 134;}Label{Position: 106, 91;Width: 96;Height: 34;Text: "Button";FontSize: 32;Color: 0.12549, 0.298039, 0.364706, 1;}Label{Position: 106, 91;Width: 96;Height: 34;Text: "Button";FontSize: 32;Color: 0.12549, 0.298039, 0.364706, 1;}';

        var result = content.split('}');
        result.pop();// removing the last empty element
        var obj = {Controls:{}};

        function nextProp(key) {
            /*if(obj.Controls.hasOwnProperty(key)) {
                var num = key.match(/\d+$/);
                if (num) {
                    return nextProp(key.replace(num[0], '') + (parseInt(num[0], 10) + 1));
                } else {
                    return nextProp(key + '1');
                }
            }*/

            return key;
        }

        for (var i = 0; i < result.length; i++) {
            var key = result[i].split('{');
            var value = result[i].replace(key[0], '') + '}';
            obj.Controls[nextProp(key[0])] = value;
        }

        var initObjectList = '<div id="prePop">';
        $.each(obj.Controls, function (k, v) {
        initObjectList += '<div class="inLineObjects">' + '<div class="key">' + k + '</div><br/>' + '<div  class="value">' + v + '</div>' +'</div>';

        });
    initObjectList += '</div>';
    $('#code').append(initObjectList)

回报:

{
    "Controls": {
        "Image": "{BackgroundImage: Image.gif;Position: 0, 0;Width: 320;Height: 480;}",
        "Image1": "{BackgroundImage: Image2.gif;Position: 0, 0;Width: 320;Height: 480;}",
        "Button": "{BackgroundImage: Button.gif;Position: 49, 80;Width: 216;Height: 71;}",
        "Button1": "{BackgroundImage: Button2.gif;Transition: View2;Position: 65, 217;Width: 188;Height: 134;}",
        "Button2": "{BackgroundImage: Button3.gif;Transition: View2;Position: 65, 217;Width: 188;Height: 134;}",
        "Label": "{Position: 106, 91;Width: 96;Height: 34;Text: \"Button\";FontSize: 32;Color: 0.12549, 0.298039, 0.364706, 1;}",
        "Label1": "{Position: 106, 91;Width: 96;Height: 34;Text: \"Button\";FontSize: 32;Color: 0.12549, 0.298039, 0.364706, 1;}"
    }
}

我的问题是上面不允许我a)。定位 {} 之外的任何内容,因为它都是一个值和 b)。它没有任何类型的递归能力来处理多个级别,即 View>button>scrollview

对此的任何帮助将不胜感激!

4

3 回答 3

1
function generalizeFunnyformat(raw) {
    "use strict";
    return ",;:{}".indexOf(raw) > -1? raw :
        " \t\r\n".indexOf(raw) > -1? " ": "a";
}

function infer(value) {
    "use strict";
    if (/^\d/.test(value)) {
        return parseFloat(value);
    } else if (/["']/.test(value)) {
        return value.substr(1, value.length - 2);
    } else {
        return value;
    }
}

function tokenEnd(state, first, second) {
    "use strict";
    state.token += first;
    if (!state.meta) {
        if (state.cursor &&
            state.cursor.hasOwnProperty(state.token)) {
            // This may be overly confident. What if primitives are also
            // allowed at the same nesting level?
            // Here we hope that coursor will be adjusted by bracket()
            // but if it doesn't happen, then we are lost.
            if (!(state.cursor[state.token] instanceof Array)) {
                state.cursor[state.token] = [state.cursor[state.token]];
            }
            state.extra = true;
            state.cursor = state.cursor[state.token];
            state.meta = state.cursor.length;
        } else {
            state.cursor[state.token] = null;
            state.meta = state.token;
        }
    } else if (state.appending) {
        if (state.cursor[state.meta] instanceof Array) {
            state.cursor[state.meta].push(state.token);
        } else {
            state.cursor[state.meta] =
                [state.cursor[state.meta], infer(state.token)];
        }
    } else {
        state.cursor[state.meta] = infer(state.token);
    }
    state.token = "";
}

function space(state, first, second) {
    "use strict";
    // noop
}

function token(state, first, secon) {
    "use strict";
    state.token += first;
}

function bracket(state, first, secon) {
    "use strict";
    var newCursor = { };
    state.cursor[state.meta] = newCursor;
    state.parents.unshift(state.cursor);
    state.cursor = newCursor;
    state.meta = "";
}

function close(state, first, second) {
    "use strict";
    state.cursor = state.parents[0];
    state.parents.shift();
    if (state.extra) {
        state.cursor = state.parents[0];
        state.parents.shift();
    }
    state.extra = false;
    state.appending = false;
}

function comma(state, first, second) {
    "use strict";
    state.appending = true;
}

function colon(state, first, second) {
    "use strict";
    state.appending = false;
}

function semi(state, first, second) {
    "use strict";
    if (state.token) {
        tokenEnd(state, "", second);
    }
    state.meta = "";
    state.appending = false;
}

function error(state, first, second) {
    "use strict";
    throw "Invalid character sequence: " + second +
        " cannot follow " + first;
}

function llparseFunnyFormat(source) {
    "use strict";
    var iterator, len = source.length - 1,
        first, second, genFirst, genSecond, handler,
        state = { result: null, cursor: { }, appending: false,
                  token: "", meta: null, parents: [], extra: false },
        parseTable = { "  ": space,
                       " :": space,
                       " a": space,
                       " ,": space,
                       " }": space,
                       " ;": space,
                       " {": space, // space
                       "aa": token,
                       "a ": tokenEnd,
                       "a:": tokenEnd,
                       "a;": tokenEnd,
                       "a{": tokenEnd,
                       "a,": tokenEnd,
                       "a}": error, // token
                       "{ ": bracket,
                       "{a": bracket,
                       "{}": bracket,
                       "{,": error,
                       "{:": error,
                       "{;": error,
                       "{{": error, // bracket
                       "} ": close,
                       "}}": close,
                       "}a": error,
                       "};": error,
                       "},": error,
                       "}:": error,
                       "}{": error, // close
                       ",,": error,
                       ",a": comma,
                       ", ": comma,
                       ",;": error,
                       ",:": error,
                       ",}": error,
                       ",{": error, // comma
                       "; ": semi,
                       ";a": semi,
                       ";}": semi,
                       ";,": error,
                       ";:": error,
                       ";;": error,
                       ";{": error, // semicolon
                       "::": error,
                       ":a": colon,
                       ": ": colon,
                       ":,": error,
                       ":;": error,
                       ":{": error,
                       ":}": error
                     };
    state.parents[0] = state.cursor;
    state.result = state.cursor;
    for (iterator = 0; iterator < len; iterator++) {
        first = source[iterator];
        second = source[iterator + 1];
        genFirst = generalizeFunnyformat(first);
        genSecond = generalizeFunnyformat(second);
        handler = parseTable[genFirst + genSecond];
        handler(state, first, second);
    }
    return state.result;
}

var test =
"View" +
"{" +
"    Name: View1;" +
"    Image" +
"    {" +
"        BackgroundImage: Image.gif;" +
"        Position: 0, 0;" +
"        Width: 320;" +
"        Height: 480;" +
"    }" +
"" +
"    Button" +
"    {" +
"        BackgroundImage: Button.gif;" +
"        Transition: View2;" +
"        Position: 49, 80;" +
"        Width: 216;" +
"        Height: 71;" +
"    }" +
"" +
"    Button" +
"    {" +
"        BackgroundImage: Button2.gif;" +
"        Position: 65, 217;" +
"        Width: 188;" +
"        Height: 134;" +
"    }" +
"" +
"    Label" +
"    {" +
"        Position: 106, 91;" +
"        Width: 96;" +
"        Height: 34;" +
"        Text: \"Button\";" +
"        FontSize: 32;" +
"        Color: 0.12549, 0.298039, 0.364706, 1;" +
"    }" +
"    Scroll" +
"    {" +
"        Position: 106, 91;" +
"        Width: 96;" +
"        Height: 34;" +
"        Button{" +
"            BackgroundImage: Button2.gif;" +
"            Position: 65, 217;" +
"            Width: 188;" +
"            Height: 134;" +
"        }" +
"        Button{" +
"            BackgroundImage: Button2.gif;" +
"            Position: 65, 217;" +
"            Width: 188;" +
"            Height: 134;" +
"        }" +
"" +
"    }" +
"" +
"}";

llparseFunnyFormat(test);

以上是我可以从您的示例中理解的公平 LL(1) 解析器。看起来它可以满足您的需求,但边缘可能很粗糙。尤其是您可能希望处理该infer()函数以更好地推断它包含的数据类型。

它也不使用eval()- 您显然不想在通过 RPC 获得的数据中使用它。

此外,如果您研究一下,parseTable您会发现语法是为这种格式设计的有多糟糕。它有太多无效产品(甚至 JSON 更好!)。因此,让为您提供这些数据的人只使用 JSON 是完全有意义的,因为他们所做的肯定更糟。

编辑:更新代码以将同名键聚合到数组中。

于 2012-12-27T19:57:18.850 回答
0

这应该有效:

str = str.replace(/(\w+)\s*\{/g, "$1:{"); // add in colon after each named object
str = str.replace(/\}(\s*\w)/g, "},$1"); // add comma before each new named object
str = str.replace(/;/g, ","); // swap out semicolons with commas
str = str.replace(/,(\s+\})/g, "$1"); // get rid of trailing commas
str = str.replace(/([\d\.]+(, [\d\.]+)+)/g, "[$1]"); // create number arrays
str = str.replace(/"/g, ""); // get rid of all double quotes
str = str.replace(/:\s+([^\[\d\{][^,]+)/g, ':"$1"');  // create strings

var obj;
eval("obj={" + str + "};");

alert(obj.View.Scroll.Button.Width);

唯一的问题是您的伪 JSON 没有唯一的属性名称。例如,您Button在 下有两个属性View。我不确定你想如何解决这个问题,尽管你可以用另一个正则表达式来解决。但这至少应该解决您最初的对象创建问题。

如果您想查看它的实际效果,请查看此 JSFiddle 。

于 2012-12-27T19:34:13.693 回答
-1

好的,这应该可以。遵循确切的步骤。

  1. 删除空格和换行符。
  2. 用 ;"" 替换分号(分号、dblquote、dblquote)
  3. 用“:”替换冒号(双引号冒号 dblquote)
  4. 用 :{" 替换左大括号
  5. 将右大括号替换为 }"

你应该完成了。

于 2012-12-27T18:26:01.967 回答