1252748
1252748

Reputation: 15369

exec not returning matches in arr[1] - n

I have a regex that I'm using to try to get some values from the getComputedStyle object. I would expect that when I run it against exec at each iteration starting at index 1 my matches would be located, but at each iteration two new elements are added to myArray and elements set before are now undefined.

var styleAsDashedStr = window.getComputedStyle(document.getElementById("container")).cssText;
var styleRe = /(?:;\s?(background.*?)\:\s?(.*?);)|(?:;\s?(font.*?)\:\s?(.*?);)|(?:;\s?(border.*?)\:\s?(.*?);)|(?:;\s?(margin.*?)\:\s?(.*?);)|(?:;\s?(padding.*?)\:\s?(.*?);)/g;
//var individuallySetStyles = styleAsDashedStr.match(styleRe);

var myArray;
while ((myArray = styleRe.exec(styleAsDashedStr)) !== null) {
    console.log(myArray);
}

First iteraction

0: "; background-blend-mode: normal;"
1: "background-blend-mode"
2: "normal"
3: undefined
4: undefined
5: undefined
6: undefined
7: undefined
8: undefined
9: undefined
10: undefined

And subsequent iterations have two elements defined, but the other 8 are not. Is there a way to get an array where elements one and two are the current captures?

Upvotes: 0

Views: 33

Answers (2)

Pointy
Pointy

Reputation: 413916

You could accumulate an object to hold the rules you find:

var myArray, rules = {};
while ((myArray = styleRe.exec(styleAsDashedStr)) !== null) {
    console.log(myArray);
    if (myArray[1] && myArray[2])
      rules[myArray[1]] = myArray[2];
}

That way you'd end up with an object that contained all the matched properties.

You could simplify your regex too (as in the answer Barmar just gave while I was editing :).

edit — a problem with your pattern is that your "stanzas" both begin and end with a ;. When you match something, the match will involve both the starting semicolon and the one that comes after it. The next match will start after the matched semicolon, so the parts of the patterns that require a leading semicolon will fail.

Upvotes: 1

Barmar
Barmar

Reputation: 782130

Use a single capture group for all the style names, not separate groups.

var styleRe = /\b((?:background|font|border|margin|padding).*?)\:\s?([^;]*?)/g;

Note that you shouldn't match ; at the beginning and end, because this will cause it to skip the first style (since there's no ; before it) and then every other style (because matching the ; at the end of one will prevent matching the ; at the beginning of the next one). I've avoided this completely by using [^;]* instead of .*? at the end.

Upvotes: 2

Related Questions