1

I have a string which contains the definition of a linear gradient ...

linear-gradient(90deg, rgba(243,231,231,1), rgba(12,0,0,0.48))

... and I need to assign both color-stop values each to a variable somehow like shown with the next pseudo code ...

const color1 = "rgba(243,231,231,1)";
const color2 = "rgba(12,0,0,0.48)";

Extracting just numbers will work too, I just need something to work with.

The thing is, I can't just count characters and substrings because my linear-gradient string-value is dynamic and may change in length, any ideas?

Peter Seliger
  • 11,747
  • 3
  • 28
  • 37
Filippo854
  • 149
  • 9

3 Answers3

1

You can use String#match.

let str = "linear-gradient(90deg, rgba(243,231,231,1), rgba(12,0,0,0.48))";
let res = str.match(/rgba\(.*?\)/g);
console.log(res);

Explanation of regular expression:

enter image description here

If you need to support both rgb and rgba, use:

str.match(/rgba?\(.*?\)/g);
Unmitigated
  • 76,500
  • 11
  • 62
  • 80
1

I'd use a regexp

https://regex101.com/r/MCdePv/1/

const str = "linear-gradient(90deg, rgba(243,231,231,1), rgba(12,0,0,0.48))";
const re = /(rgba?\(.*?\))/g; // find either rgb or rgba 
const [color1, color2] = str.match(re);
console.log(color1, color2);
mplungjan
  • 169,008
  • 28
  • 173
  • 236
1

All the approaches so far do cover the extraction of just two and only rgb/rgba based color-stop values of a gradient. But there are much more valid variants of how a linear css gradient can be expressed ... e.g. ...

-webkit-linear-gradient(top , rgb(243, 231, 231), rgba(12, 0, 0, 0.48));
-moz-linear-gradient(90deg , hsl(0, 80%, 70%), #bada55)  
-o-linear-gradient(bottom, hsl(0, 80%, 70%), #bada55) ;  
linear-gradient(135deg , red, red 60%, blue) ;

linear-gradient(yellow, blue 20%, #0f0);

linear-gradient( to left top, blue, green 40%, red ); 
linear-gradient(to top left  , red, orange, yellow, green, blue, indigo, violet) ; 
linear-gradient(to bottom right , red, rgba(255, 0, 0, 0)); 
linear-gradient(right top to left bottom, red, rgb(255, 0, 0));

Thus, the base of a generic approach has to identify the beginning(s) of any gradient-definition's color-stop.

Which means after trimming a gradient string-value one has to strip off all the unnecessary information except for the clean list of color-stop values. A (kind of validating) regular expression which features a(n optional) positive lookbehind in order to reflect the css-specification of linear gradients utilized by split does achieve the stripping from the left ...

/^(?:-\w+-)*linear-gradient\((?:.*?(?<=top|bottom|left|right|deg)\s*,\s*)*/

... whereas a rather simple regex like ... /\s*\)\s*;*$/ ... will be utilized by replace in order to strip off the unnecessary characters from the right ...

console.log([
  '  -webkit-linear-gradient(top , rgb(243, 231, 231), rgba(12, 0, 0, 0.48));',
  '-moz-linear-gradient(90deg , hsl(0, 80%, 70%), #bada55)  ',
  ' -o-linear-gradient(bottom, hsl(0, 80%, 70%), #bada55) ;  ',
  'linear-gradient(135deg , red, red 60%, blue) ;',
  '  linear-gradient(yellow, blue 20%, #0f0);',
  ' linear-gradient( to left top, blue, green 40%, red ); ',
  '   linear-gradient(to top left  , red, orange, yellow, green, blue, indigo, violet) ; ',
  ' linear-gradient(to bottom right , red, rgba(255, 0, 0, 0)); ',
  'linear-gradient(right top to left bottom, red, rgb(255, 0, 0));',
].map(str => str
  .trim()
  .split(/^(?:-\w+-)*linear-gradient\((?:.*?(?<=top|bottom|left|right|deg)\s*,\s*)*/)[1]
  .replace((/\s*\)\s*;*$/), '')
));
.as-console-wrapper { min-height: 100%!important; top: 0; }

The above example's logging shows a clean color-stop only string for each linear gradient definition.

The more complex part is how to properly distinguish/separate each possible variant of a color-stop value. The spec does help again. The splitting of values can take place at every comma-character which is followed by a non-digit character.

A regex like this ... /,(?=\D)/ ... which features a positive lookahead already does this job.

But in order to secure this task one first needs to strip every leading and trailing whitespace around every comma-character. In the end one can go and prettify each color stop value by inserting again a single space before each occurring comma-character.

A final generic approach, which extracts a list of all color-stop values from a linear css-gradient definition might look similar to the following implementation ...

function getLinearGradientColorStopValues(str) {
  return str
    .trim()
    // strip off left side.
    .split(/^(?:-\w+-)*linear-gradient\((?:.*?(?<=top|bottom|left|right|deg)\s*,\s*)*/)[1]
    // strip off right side.
    .replace((/\s*\)\s*;*$/), '')
    // strip any whitespace (sequence) before and after each comma.
    .replace((/\s*,\s*/g), ',')
    // split color-stop values at each comma which is followed by a non digit character.
    .split(/,(?=\D)/)
    // prettify/normalize each color stop value for better readability.
    .map(item => item.replace((/,/g), ', '));
}

console.log([

  '  -webkit-linear-gradient(top , rgb(243, 231, 231), rgba(12, 0, 0, 0.48));',
  '-moz-linear-gradient(90deg , hsl(0, 80%, 70%), #bada55)  ',
  ' -o-linear-gradient(bottom, hsl(0, 80%, 70%), #bada55) ;  ',
  'linear-gradient(135deg , red, red 60%, blue) ;',
  '  linear-gradient(yellow, blue 20%, #0f0);',
  ' linear-gradient( to left top, blue, green 40%, red ); ',
  '   linear-gradient(to top left  , red, orange, yellow, green, blue, indigo, violet) ; ',
  ' linear-gradient(to bottom right , red, rgba(255, 0, 0, 0)); ',
  'linear-gradient(right top to left bottom, red, rgb(255, 0, 0));',

].map(getLinearGradientColorStopValues));
.as-console-wrapper { min-height: 100%!important; top: 0; }

The OP's example/task then solves like that ...

function getLinearGradientColorStopValues(str) {
  return str
    .trim()
    // strip off left side.
    .split(/^(?:-\w+-)*linear-gradient\((?:.*?(?<=top|bottom|left|right|deg)\s*,\s*)*/)[1]
    // strip off right side.
    .replace((/\s*\)\s*;*$/), '')
    // strip any whitespace (sequence) before and after each comma.
    .replace((/\s*,\s*/g), ',')
    // split color-stop values at each comma which is followed by a non digit character.
    .split(/,(?=\D)/)
    // prettify/normalize each color stop value for better readability.
    .map(item => item.replace((/,/g), ', '));
}

const [

  colorstop1,
  colorstop2,

] = getLinearGradientColorStopValues(

  "linear-gradient(90deg, rgba(243,231,231,1), rgba(12,0,0,0.48))"
);

console.log({ colorstop1, colorstop2 });
.as-console-wrapper { min-height: 100%!important; top: 0; }
Peter Seliger
  • 11,747
  • 3
  • 28
  • 37