Reputation: 999
I'm trying to write regex that extracts all hex colors from CSS code.
This is what I have now:
Code:
$css = <<<CSS
/* Do not match me: #abcdefgh; I am longer than needed. */
.foo
{
color: #cccaaa; background-color:#ababab;
}
#bar
{
background-color:#123456
}
CSS;
preg_match_all('/#(?:[0-9a-fA-F]{6})/', $css, $matches);
Output:
Array
(
[0] => Array
(
[0] => #abcdef
[1] => #cccaaa
[2] => #ababab
[3] => #123456
)
)
I don't know how to specify that only those colors are matched which ends with punctuation, whitespace or newline.
Upvotes: 40
Views: 36077
Reputation: 4996
The accepted answer shows you how to extract hexcodes with regex, because that is the asked question.
If you, instead, want to validate if an isolated string (without preceeding #
) IS a hexcode, you can use two non-regex functions.
if (ctype_xdigit($color) && strlen($color)==6) {
// yay, it's a hex color!
}
Upvotes: 44
Reputation: 116110
Since a hex color code may also consist of 3 characters, you can define a mandatory group and an optional group of letters and digits, so the long and elaborate notation would be:
/#([a-f]|[A-F]|[0-9]){3}(([a-f]|[A-F]|[0-9]){3})?\b/
Or if you want a nice and short version, you can say that you want either 1 or 2 groups of 3 alphanumeric characters, and that they should be matched case insensitively (/i
).
/#([a-f0-9]{3}){1,2}\b/i
Instead of [a-f0-9]
you can also write [[:xdigit:]]
, if the regex engine supports this posix character class. In this case you can skip the /i
at the end, and the whole formula is only two characters more, but arguably more descriptive.
/#([[:xdigit:]]{3}){1,2}\b/
Upvotes: 63
Reputation: 489
Despite this question's age I'd like to ammend the following:
^#([[:xdigit:]]{3}){1,2}$
, where [[:xdigit:]]
is a shorthand for [a-fA-F0-9]
.
So:
<?php preg_match_all("/^#(?>[[:xdigit:]]{3}){1,2}$/", $css, $matches) ?>
Also noteworthy here is the usage of a non-capturing group (?>...)
, to ensure we don't store data in memory we never wanted to store in the first place.
Upvotes: 2
Reputation: 31417
Shorter version of GolezTrol's answer that avoids writing the character set twice:
/#([a-fA-F0-9]{3}){1,2}\b/
Upvotes: 21
Reputation: 76395
I'm not entirely sure if I got this right, but if you only want to match hex colors at the end of a CSS line:
preg_match_all('/#(?:[0-9a-fA-F]{6}|[0-9a-fA-F]{3})[\s;]*\n/',$css,$matches);
should work, all I did was add the optional \s;
char group (optional semi-colon and spaces) and a line-break character (not optional) and it seemed to work.
And as @GolezTrol pointed out #FFF;
is valid, too.
When tested on this:
$css = '/* Do not match me: #abcdefgh; I am longer than needed. */
.foo
{
color: #CAB;
background-color:#ababab;
}';
preg_match_all('/#(?:[0-9a-fA-F]{6}|[0-9a-fA-F]{3})[\s;]*\n/',$css,$matches);
var_dump($matches);
The output was:
array (array('#CAB;','#ababab;'))
Upvotes: 1