How do I parse CSS background-image
, which supports multiple values, which may be none
and functions (e.g. url()
and linear-gradient()
) with multiple comma-separated arguments? I can't seem to do this correctly with regexps. A good test case is as follows:
linear-gradient(top left, red, rgba(255,0,0,0))
, url(a)
, image(url(b.svg), 'b.png' 150dpi, 'b.gif', rgba(0,0,255,0.5))
, none
Which I'd want to convert to the following array:
[
"linear-gradient(top left, red, rgba(255,0,0,0))"
, "url(a)"
, "image(url(b.svg), 'b.png' 150dpi, 'b.gif', rgba(0,0,255,0.5))"
, "none"
]
function split (string) {
var token = /((?:[^"']|".*?"|'.*?')*?)([(,)]|$)/g;
return (function recurse () {
for (var array = [];;) {
var result = token.exec(string);
if (result[2] == '(') {
array.push(result[1].trim() + '(' + recurse().join(',') + ')');
result = token.exec(string);
} else array.push(result[1].trim());
if (result[2] != ',') return array
}
})()
}
split("linear-gradient(top left, red, rgba(255,0,0,0)), url(a), image(url" +
"(b.svg), 'b.png' 150dpi, 'b.gif', rgba(0,0,255,0.5)), none").toSource()
["linear-gradient(top left,red,rgba(255,0,0,0))", "url(a)",
"image(url(b.svg),'b.png' 150dpi,'b.gif',rgba(0,0,255,0.5))", "none"]
Looking at the current W3C Candidate Recommendation for CSS3 (in particular, see background-image and uri), it is structured as follows:
<background-image> = <bg-image> [ , <bg-image> ]*
<bg-image> = <image> | none
<image> = <url> | <image-list> | <element-reference> | <image-combination> | <gradient>
... (you can find the rest of syntax for images here)
EDIT:
You will need to parse for matching parenthese or none
then, and the former is not possible with regex. This post has a pseudo code for the algorithm: Python parsing bracketed blocks.
I know, the question is pretty old, but if you stumble over it and need another solution, you can use this one:
let mydiv = document.getElementById('mydiv'),
result = document.getElementById('result'),
bgImageArray = getBackgroundImageArray(mydiv);
console.log(bgImageArray);
result.innerHTML = bgImageArray.join('<hr>');
function getBackgroundImageArray(el)
{
// get backgroundImageStyle
let bgimg_style = getComputedStyle(el).backgroundImage,
// count for parenthesis
parenthesis = -1;
// split background by characters...
return bgimg_style.split('').reduce((str_to_split, character) => {
// if opening parenthesis
if(character === '(') {
// if first opening parenthesis set parenthesis count to zero
if(parenthesis === -1) {
parenthesis = 0;
}
// add 1 to parenthesis count
parenthesis++;
}
// for closing parenthesis reduce parenthesis count by 1
else if(character === ')') {
parenthesis--;
}
else {
// if current character is a comma and it is not inside a parenthesis, at a "split" character
if(character === ',') {
if(parenthesis === 0) {
str_to_split += '||';
return str_to_split;
}
}
}
// else keep the character
str_to_split += character;
return str_to_split;
}, '')
// split the resulting string by the split characters including whitespaces before and after to generate an array
.split(/\s*\|\|\s*/);
}
#mydiv {
height: 75px;
background-image:
/* first bg image */
linear-gradient(90deg, rgba(28,221,218,1) 0%, rgba(45,109,210,1) 35%, rgba(0,212,255,1) 100%),
/* second bg image */
-webkit-image-set(url(nothing.jpg) 1x, url(everything.png) 2x),
/* third bg image */
url('there/is/an/image.svg');
}
<div id="mydiv"></div>
<p>See in console for actual result array, below is the array splitted by <hr></p>
<div id="result"></div>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With