【问题标题】:Javascript Regex - parse structured string to object with replaceJavascript Regex - 使用替换将结构化字符串解析为对象
【发布时间】:2012-11-15 08:28:03
【问题描述】:

我的目标是解析具有特定格式的字符串以从中生成 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);

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

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"],
                    }
}

我知道您可以通过拆分然后逐行解析来做到这一点。 我喜欢完成这个大脑任务并理解如何去做的挑战:-)

【问题讨论】:

  • 您获得的对象似乎与您拥有的字符串不同步。能否请您附上一个?

标签: javascript regex parsing


【解决方案1】:

这是我的正则表达式:

\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

【讨论】:

    【解决方案2】:

    您需要更改两件事才能将所有成员都集中到一个捕获中。首先. 不匹配换行符(你不能在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
    

    【讨论】:

    • 谢谢@m.buettner!我想我已经理解了 :-) 我已经尝试过积极的前瞻,但没有尝试过消极的前瞻...(?:xxx) 非捕获组仅用于*quantifier 工作吗?
    • @StefanKrüger 您需要将前瞻和[\s\S] 组合在一起,以便检查每个字符的条件。当然,使该组不被捕获只是一种优化。
    【解决方案3】:

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

    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 :       {}
        };
    

    【讨论】:

      猜你喜欢
      • 2018-08-26
      • 2016-04-10
      • 1970-01-01
      • 1970-01-01
      • 2013-05-12
      • 2011-04-19
      • 1970-01-01
      • 2016-04-15
      • 2015-07-13
      相关资源
      最近更新 更多