Question

I'm trying to parse a hsl color string and get an hex color string from it. I tried using regex but can't figure it out. How my regexp should be look like to match and parse a hsl color string to hue, saturation and value fileds. The input will be one of the belows;

 - hsl(162,11.984633448805383%,81.17647058823529%)
 - hsl(162, 11.984633448805383%, 81.17647058823529%) <= there are
   space's between fields.

Thanks.

Was it helpful?

Solution 2

This is probably how I'd handle it

/hsl\((\d+),\s*([\d.]+)%,\s*([\d.]+)%\)/g

Regular expression visualization

OTHER TIPS

/(.*?)hsl\((\d+),(\d+)%,(\d+)%\)/.exec(color)

First of all, (.*?) is not quite necessary here. exec will look for any match in the string.

Then, to allow spaces (any number, including 0), just put \s* between the commas (I added some more too near the parentheses just in case):

/hsl\(\s*(\d+)\s*,\s*(\d+)%\s*,\s*(\d+)%\s*\)/.exec(color)

Next, you should allow periods in the regex, and if you are sure that there cannot be any invalid numbers, you can use:

/hsl\(\s*(\d+)\s*,\s*([\d.]+)%\s*,\s*([\d.]+)%\s*\)/.exec(color)

Where [\d.] is a character class which accepts both numbers and periods. Otherwise, if you can have invalid numbers and don't want to get them, use:

/hsl\(\s*(\d+)\s*,\s*(\d+(?:\.\d+)?%)\s*,\s*(\d+(?:\.\d+)?%)\)/.exec(color)

Where (\d+(?:\.\d+)?%) accepts a valid float number followed by the percentage sign.

And you might apply the regex like this:

color = 'hsl(162, 11.984633448805383%, 81.17647058823529%)';
regexp = /hsl\(\s*(\d+)\s*,\s*(\d+(?:\.\d+)?%)\s*,\s*(\d+(?:\.\d+)?%)\)/g;
res = regexp.exec(color).slice(1);
alert("Hue: " + res[0] + "\nSaturation: " + res[1] + "\nValue: " + res[2]);

jsfiddle demo.

.slice(1) removes the string match so that you have only the captured groups in the res array.

How about:

/hsl\((\d+),\s*(\d+(?:\.\d+))%,\s*(\d+(?:\.\d+))%\)/

explanation:

The regular expression:

(?-imsx:/hsl\((\d+),\s*(\d+(?:\.\d+))%,\s*(\d+(?:\.\d+))%\)/)

matches as follows:

NODE                     EXPLANATION
----------------------------------------------------------------------
(?-imsx:                 group, but do not capture (case-sensitive)
                         (with ^ and $ matching normally) (with . not
                         matching \n) (matching whitespace and #
                         normally):
----------------------------------------------------------------------
  /hsl                     '/hsl'
----------------------------------------------------------------------
  \(                       '('
----------------------------------------------------------------------
  (                        group and capture to \1:
----------------------------------------------------------------------
    \d+                      digits (0-9) (1 or more times (matching
                             the most amount possible))
----------------------------------------------------------------------
  )                        end of \1
----------------------------------------------------------------------
  ,                        ','
----------------------------------------------------------------------
  \s*                      whitespace (\n, \r, \t, \f, and " ") (0 or
                           more times (matching the most amount
                           possible))
----------------------------------------------------------------------
  (                        group and capture to \2:
----------------------------------------------------------------------
    \d+                      digits (0-9) (1 or more times (matching
                             the most amount possible))
----------------------------------------------------------------------
    (?:                      group, but do not capture:
----------------------------------------------------------------------
      \.                       '.'
----------------------------------------------------------------------
      \d+                      digits (0-9) (1 or more times
                               (matching the most amount possible))
----------------------------------------------------------------------
    )                        end of grouping
----------------------------------------------------------------------
  )                        end of \2
----------------------------------------------------------------------
  %,                       '%,'
----------------------------------------------------------------------
  \s*                      whitespace (\n, \r, \t, \f, and " ") (0 or
                           more times (matching the most amount
                           possible))
----------------------------------------------------------------------
  (                        group and capture to \3:
----------------------------------------------------------------------
    \d+                      digits (0-9) (1 or more times (matching
                             the most amount possible))
----------------------------------------------------------------------
    (?:                      group, but do not capture:
----------------------------------------------------------------------
      \.                       '.'
----------------------------------------------------------------------
      \d+                      digits (0-9) (1 or more times
                               (matching the most amount possible))
----------------------------------------------------------------------
    )                        end of grouping
----------------------------------------------------------------------
  )                        end of \3
----------------------------------------------------------------------
  %                        '%'
----------------------------------------------------------------------
  \)                       ')'
----------------------------------------------------------------------
  /                        '/'
----------------------------------------------------------------------
)                        end of grouping
----------------------------------------------------------------------

This is a very old question, but I just wanted to provide an up-to-date answer.

My solution can be a bit daunting to look at, but I believe it comes close to the extent of possible values, including the new CSS Color Level 4.

/** Regular expression for valid CSS number */
const cssNumberMatcher = /[+-]?(?=\.\d|\d)\d*(?:\.\d+)?(?:[eE][+-]?\d+)?/

/** Regular expression for color component separator */
const separatorMatcher = /(?=[,\s])\s*(?:,\s*)?/

/** Regular expression for alpha separator */
const alphaSeparatorMatcher = /\s*[,\/]\s*/

const num = cssNumberMatcher.source
const sep = separatorMatcher.source
const asep = alphaSeparatorMatcher.source

/**
 * Regular expression for HSL color string
 *
 * The pattern is less strict than actual CSS, mainly for
 * performance reasons. Notably, it does NOT impose
 * consistent separator (comma vs. space)
 */
const hslMatcher = new RegExp(
  `hsla?\\(\\s*(${num}(?:deg|rad|grad|turn)?)${sep}(${num})%${sep}(${num})%(?:${asep}(${num}%?))?\\s*\\)`,
  'i',
)

/**
 * Attempts to match the given color string with the HSL
 * string pattern, and extracts the color components
 *
 * Since the standard unit for S and L values is percent,
 * the % sign is not included in the captured values.
 *
 * @param colorString
 * @returns an array containing the matched HSL values, or `null`
 */
function matchHslString(colorString) {
  const match = hslMatcher.exec(colorString)
  return match?.slice(1) ?? null
}

It's up to you now how to generate the hex string from those HSL values. You will need to transform it first to RGB model, then to Hex.

Here are the supported formats (up to CSS Color Level 4):

  const valid = [
    'hsl(240, 100%, 50%)', // comma separated
    'hsl(240, 100%, 50%, 0.1)', // comma separated with opacity
    'hsl(240, 100%, 50%, 10%)', // comma separated with % opacity
    'hsl(240,100%,50%,0.1)', // comma separated without spaces
    'hsl(180deg, 100%, 50%, 0.1)', // hue with 'deg'
    'hsl(3.14rad, 100%, 50%, 0.1)', // hue with 'rad'
    'hsl(200grad, 100%, 50%, 0.1)', // hue with 'grad'
    'hsl(0.5turn, 100%, 50%, 0.1)', // hue with 'turn'
    'hsl(-240, -100%, -50%, -0.1)', // negative values
    'hsl(+240, +100%, +50%, +0.1)', // explicit positive sign
    'hsl(240.5, 99.99%, 49.999%, 0.9999)', // non-integer values
    'hsl(.9, .99%, .999%, .9999)', // fraction w/o leading zero
    'hsl(0240, 0100%, 0050%, 01)', // leading zeros
    'hsl(240.0, 100.00%, 50.000%, 1.0000)', // trailing decimal zeros
    'hsl(2400, 1000%, 1000%, 10)', // out of range values
    'hsl(-2400.01deg, -1000.5%, -1000.05%, -100)', // combination of above
    'hsl(2.40e+2, 1.00e+2%, 5.00e+1%, 1E-3)', // scientific notation
    'hsl(240 100% 50%)', // space separated (CSS Color Level 4)
    'hsl(240 100% 50% / 0.1)', // space separated with opacity
    'hsla(240, 100%, 50%)', // hsla() alias
    'hsla(240, 100%, 50%, 0.1)', // hsla() with opacity
    'HSL(240Deg, 100%, 50%)', // case insensitive
  ]

The snippets above were taken from my library simpler-color.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top