正则表达式优化和最佳实践

时间:2019-05-10 12:19:16

标签: javascript regex regex-lookarounds regex-group regex-greedy

我需要从旧版界面解析信息。我们无法更新旧消息。我对正则表达式不是很精通,但是我设法写了一个能满足我期望的表达式。我只需要同行评审和反馈以确保它是干净的。

来自旧系统的消息返回的值类似于下面的示例。

%name0=value
%name1=value
%name2=value
Expression: /\%(.*)\=(.*)/g;
var strBody = body_text.toString();
var myRegexp = /\%(.*)\=(.*)/g;
var match = myRegexp.exec(strBody);
var objPair = {};

while (match != null) {
    if (match[1]) {
        objPair[match[1].toLowerCase()] = match[2];
    }
    match = myRegexp.exec(strBody);
}

此代码有效,我可以在名称/值的中间添加部分匹配项而不会造成任何破坏。我必须假定字符的任何组合都可能出现在“值”匹配中。这意味着它在消息中可能具有等号和百分号。

  • 这够干净吗?
  • 是否有可能破坏表达式?

2 个答案:

答案 0 :(得分:2)

您的表达式很好,用两个捕获组将其包装起来很容易获得所需的变量和值。

您可能不需要转义一些字符,它仍然可以工作。

如果需要,您可以使用this tool并测试/编辑/修改/更改表达式:

%(.+)=(.+)

由于您的数据结构合理,因此您也可以使用字符串分割来实现,并根据需要获得相同的期望输出。

RegEx描述图

此图显示了表达式的工作方式,您可以在此link中可视化其他表达式:

enter image description here

JavaScript测试

const regex = /%(.+)=(.+)/gm;
const str = `%name0=value
%name1=value
%name2=value`;
let m;

while ((m = regex.exec(str)) !== null) {
    // This is necessary to avoid infinite loops with zero-width matches
    if (m.index === regex.lastIndex) {
        regex.lastIndex++;
    }
    
    // The result can be accessed through the `m`-variable.
    m.forEach((match, groupIndex) => {
        console.log(`Found match, group ${groupIndex}: ${match}`);
    });
}

性能测试

此JavaScript代码段使用简单的100万次for循环来显示该表达式的性能。

const repeat = 1000000;
const start = Date.now();

for (var i = repeat; i >= 0; i--) {
	const string = '%name0=value';
	const regex = /(%(.+)=(.+))/gm;
	var match = string.replace(regex, "\nGroup #1: $1 \n Group #2: $2 \n Group #3: $3 \n");
}

const end = Date.now() - start;
console.log("YAAAY! \"" + match + "\" is a match  ");
console.log(end / 1000 + " is the runtime of " + repeat + " times benchmark test.  ");

答案 1 :(得分:2)

首先,请不要转义不需要转义的字符:%(.*)=(.*)

表达式的问题:值中的等号会破坏解析器。 %name0=val=ue将导致name0=val = ue而不是name0 = val=ue

一个可能的解决方法是通过添加问号%(.*?)=(.*)

来使第一次重复变得懒惰。

但这不是最佳选择,因为不需要回溯。通过使用否定的字符类,您可以做得更好:%([^=]*)=(.*)

最后,如果不允许使用空名称,则将第一个星号替换为加号:%([^=]+)=(.*)

这是很好的资源:Regex Tutorial - Repetition with Star and Plus

相关问题