Elie G.
Elie G.

Reputation: 1723

Javascript Regex Replace - Random numbers appear

My Goal:
I'm trying to parse css string to retrieve different parts like css rules, imports, comments, ...

What I've done:
My function starts by retrieving comments, then it retrieves the imports and finally it retrieves the rules blocks.
Once these parts are retrieved, each parts is logged to the console.

My Problem:
My problem is when I test it, it seems like my code generates random numbers when the rules blocks part is logged to the console.

My Code:

function output(css) {
    if(typeof css === 'string') {
        var current = css;
        // remove comments
        var comments = [];
        current = current.replace(/\s*\/\*[^*]*\*+([^/*][^*]*\*+)*\/|^\/\/[^\n]*\n?/gim, c=>comments.push(c.trim()));

        // retrieve @ imports
        var imports = [];
        current = current.replace(/@[^;{]+;/gi, imp => imports.push(imp.trim()));

        // retrieve rules blocks
        var rulesBlocks = [];
        current = current.replace(/[^};]+{[^{]*}/gi, block => {
            rulesBlocks.push(block.trim());
        });
        console.log(comments, imports, rulesBlocks);
    }
}

var css = document.getElementById('css').innerText;

output(css);
<pre id="css"><code>
#id, .class {
	#id {
	}
}
/**
*/
@import url('http://www.test.com/test.min.js/');
/*
@import url('http://www.test.com/test.min.js/');
*/
/***/
//#id, .class {
#id, .class {
	#id {
		& {
		}
	}
}
#id, .class {
	#id {
	}
}
declaration {
    data: test;
}
declaration2 declaration {
    data
}

@font-face {
    font-family: myFirstFont;
    src: url(sansation_light.woff);
}
@font-face {
    font-family: myFirstFont;
    src: url(sansation_light.woff);
}
</code></pre>

As you can see if you run it, the console shows random numbers in this line:
"1\n123\n4#id, .class {\n\t#id {\n\t\t& {\n\t\t}\n\t}\n}"
Why it generates random numbers? Why the console shows 1, 123 and 4?

Upvotes: 2

Views: 57

Answers (1)

Karl Reid
Karl Reid

Reputation: 2217

Because array push returns the new length of the array, and you are using that return value as the replacement.

You can specify a function as the second parameter. In this case, the function will be invoked after the match has been performed. The function's result (return value) will be used as the replacement string.

So:

current = current.replace(/@[^;{]+;/gi, imp => imports.push(imp.trim()));

will replace every instance of the expression with the new length of imports.

If you want to avoid the problem, you could use Washington Guedes' suggestion in the comments of adding &&''; after the push, or just return imp (etc.) in the replace function, or rewrite the function to use the more idiomatic exec method.

Upvotes: 2

Related Questions