简体   繁体   中英

Javascript RegEx Lazy match

I am trying to find for loop pattern in javascript code, and replace syntax (from : to in), using below regex way,

var str="for(var x in []) for(var y in [])";

str.replace( new RegExp( '(for\\s*\\(.+\\s+):(\\s+.+\\))', 'ig' ), "\$1in\$2" )

ie

for(var x : list)
{
 // something
}

with

for(var x in list)
{
 // something
}

However I am facing issues when there are multiple for loops in same line.

for(var x : list) { for(var y : list) {
     // something
 }
}

which is valid syntax, however due to Greedy regex approach it converts as below:

for(var x : list) { for(var y in list) {
         // something
 }
}

I tried to explore lazy regex syntax but couldn't make it work. How can I achieve this ?

You could add some lazy quantifiers to all * and + . and take for as part of the replacement, because of matching.

 var str = "for(var x : []) for(var y : [])"; console.log(str.replace(/for\\s*?(\\(.+?\\s+?):(\\s+?.+?\\))/ig, "for $1in$2")); 

A bit shorter and it includes for in the first group.

 var str = "for(var x : []) for(var y : [])"; console.log(str.replace(/(for\\s*?\\(.+?):(.+?\\))/ig, "$1in$2")); 

Instead of using lazy quantifiers, you can use negated character set as they perform better and you can use this regex,

(for\s*\([^:]+):([^)]+\))

and replace it with,

$1 in $2

Also, you don't have to use .+\\\\s+ as this is redundant and instead you can just write .+? and even better to use negated character set for it to work faster and similarly after : you can write \\\\s+.+ as .+? but again negated character class is better choice like I mentioned in my answer.

Another point that could lead you into issues is, you should not use this \\$1in\\$2 for replacement, and instead use $1 in $2 firstly you don't need to escape $ as \\$ and secondly because in case your for loop is like this, for(var x:list) ie without having space between colon and surrounding variables, then the output of replacement you may get is for(var xinlist) which would make it invalid. Which is why I suggested above in my answer to replace with $1 in $2 so in has space at both sides.

Regex Demo

JS codes,

 const s = `for(var x : list) { // something } for(var x : list) { for(var y : list) { // something } }` console.log(s.replace(/(for\\s*\\([^:]+):([^)]+\\))/g, '$1 in $2')) 

The lazy behaviour can be achived with a ? after the quantifier.

const str = "for(var x : list) { for(var y : list) {"
str.replace( new RegExp( '(for\\s*?\\(.+?\\s+?):(\\s+.+\\))', 'ig' ), "\$1in\$2" )

btw. JavaScript RegEx literals are much easier to read:

str.replace( /(for\s*?\(.+?\s+?):(\s+.+\))/ig, "\$1in\$2" )

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM