-
-
Save olmokramer/82ccce673f86db7cda5e to your computer and use it in GitHub Desktop.
/(#([0-9a-f]{3}){1,2}|(rgba|hsla)\(\d{1,3}%?(,\s?\d{1,3}%?){2},\s?(1|0?\.\d+)\)|(rgb|hsl)\(\d{1,3}%?(,\s?\d{1,3}%?\)){2})/i |
@olmokramer Sorry but of all the items in your bullet list above, only the last item seems to be true as regards valid values, at least nowadays (I know you posted a couple of years back)
- rgb() and rgba() are now interchangeable, and so are hsl() and hsla(). They are now considered aliases.
- second item is still partially true, but for different reason. rgb() accepts percentages. But only when ALL 3 color components are %.
- rgb() accepts out of range values, including negative. The renderer just clamps it into the accepted range. This includes alpha value.
Also I would like to point out that in general, a single regex that captures all possible values across all color spaces, hex, named colors, etc. is difficult to formulate especially if:
- you need to retrieve values of the color components from capturing groups
- you need to impose strict rules per color model (rgb vs. hsl)
It is still better to test the color string against different specialized patterns to determine which one matches (if any).
none keyword allowed in latest syntax (while values are space seprated not comma separated ) hen how to capture these
following are valid css
- rgb(none 10 20)
- hsl(120deg none none)
- hwb(200 none 0.5)
Here's the regular expression I've got. It recognizes hex-colors and a few simple color functions. I'm using it in a remarkjs
plugin to add color squares next to colors, similar to how GitHub does this: #4F82A9
.
/^(#(?:[0-9a-fA-F]{3}){1,2}|#(?:[0-9a-fA-F]{4}){1,2}|rgba?\(\s*\d*(?:\.\d*)?\s*,\s*\d*(?:\.\d*)?\s*,\s*\d*(?:\.\d*)?\s*(?:,\s*\d*(?:\.\d*)?%?\s*)?\)|rgba?\(\s*(?:\d*(?:\.\d*)?%|0)\s*,\s*(?:\d*(?:\.\d*)?%|0)\s*,\s*(?:\d*(?:\.\d*)?%|0)\s*(?:,\s*\d*(?:\.\d*)?%?\s*)?\)|rgba?\(\s*\d*(?:\.\d*)?%?\s+\d*(?:\.\d*)?%?\s+\d*(?:\.\d*)?%?\s*(?:\/\s*\d*(?:\.\d*)?%?\s*)?\)|hsla?\(\s*\d*(?:\.\d*)?(?:deg|grad|rad|turn)?\s*,\s*(?:\d*(?:\.\d*)?%|0)\s*,\s*(?:\d*(?:\.\d*)?%|0)\s*(?:,\s*\d*(?:\.\d*)?%?\s*)?\)|h(?:sla?|wb)\(\s*\d*(?:\.\d*)?(?:deg|grad|rad|turn)?\s+\d*(?:\.\d*)?%?\s+\d*(?:\.\d*)?%?\s*(?:\/\s*\d*(?:\.\d*)?%?\s*)?\))$/
const num = String.raw`\d*(?:\.\d*)?`;
const percent = `(?:${num}%|0)`;
const numOrPercent = `${num}%?`;
const alpha = numOrPercent;
const hue = `${num}(?:deg|grad|rad|turn)?`;
const colorFuncs = [
// Hex colors: #000, #0000, #000000, #00000000
`#(?:[0-9a-fA-F]{3}){1,2}`,
`#(?:[0-9a-fA-F]{4}){1,2}`,
// Legacy rgb/rgba: rgba(1,2,3,0.5)
String.raw`rgba?\(\s*${num}\s*,\s*${num}\s*,\s*${num}\s*(?:,\s*${alpha}\s*)?\)`,
String.raw`rgba?\(\s*${percent}\s*,\s*${percent}\s*,\s*${percent}\s*(?:,\s*${alpha}\s*)?\)`,
// Modern rgb/rgba: rgba(1 2 3/0.5)
String.raw`rgba?\(\s*${numOrPercent}\s+${numOrPercent}\s+${numOrPercent}\s*(?:/\s*${alpha}\s*)?\)`,
// Legacy hsl/hsla: hsl(1deg,2%,3%,0.5)
String.raw`hsla?\(\s*${hue}\s*,\s*${percent}\s*,\s*${percent}\s*(?:,\s*${alpha}\s*)?\)`,
// Modern hsl/hsla/hwb: hsla(1deg 2% 3%/0.5)
String.raw`h(?:sla?|wb)\(\s*${hue}\s+${numOrPercent}\s+${numOrPercent}\s*(?:/\s*${alpha}\s*)?\)`,
];
export const ColorRegex = new RegExp(`^(${colorFuncs.join("|")})$`);
This regex doesn't recognize keywords and more advanced color functions, but for my use case I don't need that much specificity. You can extend this further by looking at what values are valid in the CSS specification.
@khalilgharbaoui That's cool, always nice to see your work being used :)
Please be aware, though, that most of the regexes here still contain pretty serious bugs.
For example, a lot of patterns have a clause similar to
(rgb|hsl)a?\((-?\d+%?[,\s]+){2,3}\s*[\d\.]+%?\)
, but this is obviously wrong for multiple reasons:rgb(0, 0, 0, 0)
andrgba(0, 0, 0)
, thoughrgb
can only have 3 arguments andrgba
must have 4 arguments.rgb(0, 0%, 0%)
, though the arguments torgb
cannot be percentages. Joining thergb
andhsl
cases was never a good idea, becausergb
must always reject percentages, whilehsl
must accept them.rgb(-1, -1, -1)
, though the minimum allowed value is 0.rgb(999, 999, 999)
, though the maximum allowed value is 255.hsl(0%, 0, 0)
, though the first argument cannot be a percentage, and the second and third argument must be percentages.To name a few. This is not a problem if you just want to find correctly formatted colours in a body of text, but it is a problem if the regular expression is used to validate colours. The
$
everywhere make it impossible to use this regex to find all colours in a body of text, though, as it will only find them at the end of the string, so the only use case that's left is validation, which, as I pointed out, the regex isn't very good at.So I would suggest you decide what is your use case for the package, and either (or both :)
$
with\b
so that the regex can be used for searching again.