2

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" )

i.e.

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 ?

7
  • Regex is no good for dealing with nested structures. I can make it work for current scenario but it may still fail in general when you have more nesting patterns. Commented May 3, 2019 at 8:04
  • Couldn't you just do it like str.split(':').join(' in ')? Or you only want to do it as part of for loops? Commented May 3, 2019 at 8:10
  • Icepickle, No, because ':' is used in various ways i.e. for objects ==> var objectA = {'A','Apple','B':'Banana'}; Commented May 3, 2019 at 8:11
  • @PushpeshKumarRajwanshiHow shall I handle this thn ? Using recursive match ? Or any other possible way ? Commented May 3, 2019 at 8:12
  • 1
    @Pratik: Added as answer Please check. Commented May 3, 2019 at 8:20

3 Answers 3

2

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"));

Sign up to request clarification or add additional context in comments.

1 Comment

Writing .+?\s+? is redundant can be just written as .+? and same for \s+?.+?
1

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) i.e. 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'))

Comments

0

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" )

1 Comment

"achieve using" what?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.