Javascript Regex - 使用replace将结构化字符串解析为对象

时间:2012-11-27 16:44:43

标签: javascript regex parsing

我的目标是解析一个具有特定格式的字符串,以便从中生成一个javascript对象结构。

一个想法是使用带有函数作为参数的String.replace。 所以在功能中你可以得到比赛的所有部分。 我的测试/例子到现在为止:

字符串:

    !Norm: DIN 7985;
        M2: 2, 2, 2;
        M3:3,3;
        M10: 20,25;
!Norm: DIN 7985 TX;
    M4: 4,  4    , 4;

我的测试代码:

console.clear();
var sTmp = "!Norm: DIN 7985;\n    M2: 2, 2, 2;\n    M3:3,3;\n    M10: 20,25;\n     !Norm: DIN 7985 TX;\n    M2: 6,    10    , 16;";
//console.log(sTmp);

function replacer(match, p1, p2, p3, p4, offset, string){
    //console.log("-");
    console.log("match:", match);
    console.log("p1:", p1);
    console.log("p2:", p2);
    console.log("p3:", p3);
    console.log("p4:", p4);
    console.log("offset:", offset);
    console.log("string:", string);
    return "#";
}
//(?=!Norm:\s?(.+);\s+)
sTmp.replace(/\s*!Norm:\s?(.+);\s+(M\d+:.*\s*;)/g, replacer);

(在萤火虫中测试) 控制台日志(shortend):

match: !Norm: DIN 7985; M2: 2, 2, 2;
p1: DIN 7985
p2: M2: 2, 2, 2;
p3: 0
p4: !Norm: DIN 7985; M2: 2, 2, 2; M3:3,3; M10: 20,25; ....
offset: undefined
string: undefined
match: !Norm: DIN 7985 TX; M4: 4, 4 , 4;
p1: DIN 7985 TX
p2: M4: 4, 4 , 4;
p3: 52
p4: !Norm: DIN 7985; M2: 2, 2, 2; M3:3,3; M10: 20,25; !Norm: DIN 7985 TX; M4: 4, 4 , 4;
....

所以我可以看到这个想法有效 - 它符合规范,我将信息放在一个子字符串中。 现在有M3:......零件。 那么是否有一个选项来指定(M\d+:.*\s*;)部分与下一个匹配!Norm:而不是;在第一次出现? 我认为应该可以用一个先行或其他什么方式?

这个想法背后的目标是从字符串中生成这样的javascript对象:

    oDataTmp = {
    DIN 7985 :      {
                        M2        : ["2", "2", "2"],
                        M3        : ["3", "3"],
                        M10       : ["20", "25"],
                    }
    DIN 7985 TX :   {
                        M4        : ["4", "4", "4"],
                    }
}

我知道您可以通过拆分执行此操作,然后逐行解析。 我喜欢完成这项大脑工作的挑战,并了解如何做到这一点: - )

3 个答案:

答案 0 :(得分:2)

这是我的正则表达式:

\s*!\w+:\s*([^;]+);\s*((?:\s*[^:!]+:[^;]+;)+)

它有以下匹配组:

  • 第1组:DIN部分。
  • 第2组:当前的所有剩余设置!Norm。

此正则表达式并不特别指望关键字NORM。所以它可能是其他任何东西。如果要捕获它,只需在第一个\ w +。

周围添加括号

说明:

/            # start regex
\s*          # match optional whitespace
!\w+:        # match word between '!' and ':'
\s*          # match optional whitespace
([^;]+);     # capture group 1 - match all characters (without ';') up to the next ';'
\s*          # match optional whitespace
(            # start capture group 2
    (?:          # group (non-capture)
        \s*          # match optional whitespace
        [^:!]+:      # match all characters (without ':' and '!') up to the next ':'
        [^;]+;       # match all characters (without ';') up to the next ';'
    )+           # group end; match this group 1 to n times
)            # end capture group 2
/g           # end regex; set g-Flag for global

答案 1 :(得分:1)

您需要更改两件事以将所有成员合并为一个捕获。首先.与换行符不匹配(并且您无法在JavaScript中更改它)。但[\s\S]确实如此。是的,使用否定前瞻,我们可以确保我们不消耗下一个!Norm

/\s*!Norm:\s?(.+);\s+((?:(?![!]Norm)[\s\S])*)/g

我已将文字!包装在方括号中,以明确它是文字,并将其从!设置为负前瞻语法的一部分。你可以省略方括号,这只是为了便于阅读。所以基本上这将填充最后一次捕获任意字符,只要它们不启动新的!Norm

然后你可以继续,并从最后一次捕获中读取单个属性和值。

说明:

/            # start regex
\s*          # match optional whitespace
!Norm:       # match '!Norm:'
\s?          # match optional whitespace
(.+);        # capture group 1 - match all characters (whitout '\n') up to the next ';'
\s+          # match 1..n whitespaces
(            # start capture group 2
    (?:          # group (non-capture)
        (?!          # negative lookahead
            [!]Norm      # match '!Norm'
        )            # end negative lookahead
        [\s\S]       # match a white space or other than white space character
                     # this group match a single character as long as it dont start are new !Norm
    )*           # group end; match this group 0..n times
)            # end capture group 2
/g           # end regex; set g-Flag for global

答案 2 :(得分:0)

所以在这里我有一个完整的解决方案 使用的正则表达式来自两个答案的组合:

console.clear();
var sData = "!Norm: DIN 933;\n !Norm: DIN 7985;\n    M2: 2, 2, 2;\n    M3:3,3;\n    M10: 20,25;\n     !Norm: DIN 7985 TX;\n    M2: 6,    10    , 16;";
console.log(sTmp);

var oData = {};

// Parse sData with help of Regex replace
sData.replace(/\s*!Norm:\s*([^;]+);\s*((?:(?![!]Norm)[\s\S])*)/g, 
    function replacer(match, sNorm, sScrews, offset, string) {
        //console.log("match:", match);
        //console.log("sNorm:", sNorm);
        //console.log("sScrews:", sScrews);
        //console.log("offset:", offset);
        //console.log("string:", string);

        var oScrews = {};

        sScrews.replace(/\s*(M\d+):\s*([^;]+);\s*/g, 
            function(match, sScrewSize, sScrewList, offset, string) {
                //console.log("match:", match);
                //console.log("sScrewSize:", sScrewSize);
                //console.log("sScrewList:", sScrewList);
                //console.log("offset:", offset);
                //console.log("string:", string);

                oScrews[sScrewSize] = sScrewList.split(/[\s,]+/);

                return "§";
            });

        oData[sNorm] = oScrews;

        return "#";
    });

console.log("oData: ");
console.dir(oData);

结果对象(在控制台中验证):

oData = {
    DIN 7985 :      {
                        M10 : ["20", "25"],
                        M2  : ["2", "2", "2"],
                        M3  : ["3", "3"],
                    }
    DIN 7985 TX :   {
                        M4  : ["4", "4", "4"],
                    }
    DIN 933 :       {}
    };