Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>Parsing CSS can be far more complex there are few things to remember:</p> <ul> <li>Avoid writing a parser - someone else will probably have written one already (search).</li> <li>Your parser will likely fail if you don't control the input source or test it thoroughly with input samples.</li> <li>In the case of gradients you can have "angles" as well as "corner-sides" like "right".</li> <li>There are an unknown number of color stops (minimum 1).</li> <li>You will never likely want to include the complete list of CSS colors in a regular expression (e.g. <code>red</code>, <code>blue</code>, etc).</li> <li>You should check out <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/linear-gradient" rel="noreferrer">MDN</a> for details of syntax variations, the sample code below only supports the standard syntax.</li> <li>Regular expression support and bugs are different depending on the browser and version - test your target browsers with all your samples.</li> </ul> <p>OK, so here is a crazy example of how you "could" parse the gradient using regular expressions - I'm not saying you should.</p> <p>Here I build my regular expressions in code to keep some level of readability and maintainability of the code.</p> <p>The final output of the <code>test_this_thing</code> functions <code>console.log(result);</code> is as follows:</p> <p>Input:</p> <p><code>background-image:linear-gradient(to right bottom, #FF0000 0%, #00FF00 20px, rgb(0, 0, 255) 100%);</code></p> <p>Output:</p> <pre><code>{ original:"to right bottom, #FF0000 0%, #00FF00 20px, rgb(0, 0, 255) 100%", line:"to right bottom", sideCorner:"right bottom", colorStopList:[ { color:"#FF0000", position:"0%" }, { color:"#00FF00", position:"20px" }, { color:"rgb(0, 0, 255)", position:"100%" } ] } </code></pre> <p>Note the output includes the <code>original</code> property - this looks like the input - but if part of the input wasn't matched the <code>input</code> and <code>original</code> values would be different; noting an possible error in the parser.</p> <p>Here is a source:</p> <pre><code> /** * Utility combine multiple regular expressions. * * @param {RegExp[]|string[]} regexpList List of regular expressions or strings. * @param {string} flags Normal RegExp flags. */ var combineRegExp = function (regexpList, flags) { var i, source = ''; for (i = 0; i &lt; regexpList.length; i++) { if (typeof regexpList[i] === 'string') { source += regexpList[i]; } else { source += regexpList[i].source; } } return new RegExp(source, flags); }; /** * Generate the required regular expressions once. * * Regular Expressions are easier to manage this way and can be well described. * * @result {object} Object containing regular expressions. */ var generateRegExp = function () { // Note any variables with "Capture" in name include capturing bracket set(s). var searchFlags = 'gi', // ignore case for angles, "rgb" etc rAngle = /(?:[+-]?\d*\.?\d+)(?:deg|grad|rad|turn)/, // Angle +ive, -ive and angle types rSideCornerCapture = /to\s+((?:(?:left|right)(?:\s+(?:top|bottom))?))/, // optional 2nd part rComma = /\s*,\s*/, // Allow space around comma. rColorHex = /\#(?:[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/, // 3 or 6 character form rDigits3 = /\(\s*(?:[0-9]{1,3}\s*,\s*){2}[0-9]{1,3}\s*\)/,// "(1, 2, 3)" rDigits4 = /\(\s*(?:[0-9]{1,3}\s*,\s*){3}[0-9]{1,3}\s*\)/,// "(1, 2, 3, 4)" rValue = /(?:[+-]?\d*\.?\d+)(?:%|[a-z]+)?/,// ".9", "-5px", "100%". rKeyword = /[_A-Za-z-][_A-Za-z0-9-]*/,// "red", "transparent", "border-collapse". rColor = combineRegExp([ '(?:', rColorHex, '|', '(?:rgb|hsl)', rDigits3, '|', '(?:rgba|hsla)', rDigits4, '|', rKeyword, ')' ], ''), rColorStop = combineRegExp([rColor, '(?:\\s+', rValue, ')?'], ''),// Single Color Stop, optional value. rColorStopList = combineRegExp(['(?:', rColorStop, rComma, ')*', rColorStop], ''),// List of color stops min 1. rLineCapture = combineRegExp(['(?:(', rAngle, ')|', rSideCornerCapture, ')'], ''),// Angle or SideCorner rGradientSearch = combineRegExp([ '(', rLineCapture, ')', rComma, '(', rColorStopList, ')' ], searchFlags),// Capture 1:"line", 2:"angle" (optional), 3:"side corner" (optional) and 4:"stop list". rColorStopSearch = combineRegExp([ '\\s*(', rColor, ')', '(?:\\s+', '(', rValue, '))?', '(?:', rComma, '\\s*)?' ], searchFlags);// Capture 1:"color" and 2:"position" (optional). return { gradientSearch: rGradientSearch, colorStopSearch: rColorStopSearch }; }; /** * Actually parse the input gradient parameters string into an object for reusability. * * * @note Really this only supports the standard syntax not historical versions, see MDN for details * https://developer.mozilla.org/en-US/docs/Web/CSS/linear-gradient * * @param regExpLib * @param {string} input Input string in the form "to right bottom, #FF0 0%, red 20px, rgb(0, 0, 255) 100%" * @returns {object|undefined} Object containing break down of input string including array of stop points. */ var parseGradient = function (regExpLib, input) { var result, matchGradient, matchColorStop, stopResult; matchGradient = regExpLib.gradientSearch.exec(input); if (matchGradient !== null) { result = { original: matchGradient[0], colorStopList: [] }; // Line (Angle or Side-Corner). if (!!matchGradient[1]) { result.line = matchGradient[1]; } // Angle or undefined if side-corner. if (!!matchGradient[2]) { result.angle = matchGradient[2]; } // Side-corner or undefined if angle. if (!!matchGradient[3]) { result.sideCorner = matchGradient[3]; } // Loop though all the color-stops. matchColorStop = regExpLib.colorStopSearch.exec(matchGradient[4]); while (matchColorStop !== null) { stopResult = { color: matchColorStop[1] }; // Position (optional). if (!!matchColorStop[2]) { stopResult.position = matchColorStop[2]; } result.colorStopList.push(stopResult); // Continue searching from previous position. matchColorStop = regExpLib.colorStopSearch.exec(matchGradient[4]); } } // Can be undefined if match not found. return result; }; var test_this_thing = function () { var result, regExpLib = generateRegExp(), input = 'background-image:linear-gradient(to right bottom, #FF0000 0%, #00FF00 20px, rgb(0, 0, 255) 100%);', rGradientEnclosedInBrackets = /.*gradient\s*\(((?:\([^\)]*\)|[^\)\(]*)*)\)/,// Captures inside brackets - max one additional inner set. match = rGradientEnclosedInBrackets.exec(input); if (match !== null) { // Get the parameters for the gradient result = parseGradient(regExpLib, match[1]); } else { result = "Failed to find gradient"; } console.log(result); }; test_this_thing(); </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload