Re: Factor

Factor: the language, the theory, and the practice.

ChuckNorris is a Color

Saturday, November 9, 2013

#colors

I just came across a fun question asking why does HTML think ‘chucknorris’ is a color on StackOverflow. This is called “Flex Hex” and is described in detail in a little rant about Microsoft Internet Explorer’s color parsing.

It turns out these are all valid colors:

chucknorris sick crap

I thought it would be fun to support parsing colors in this (arguably broken) format in Factor. The algorithm basically breaks down into three parts:

1. Convert non-hexadecimal digits to zero.

: hex-only ( str -- str' )
    [ dup hex-digit? [ drop CHAR: 0 ] unless ] map ;

2. Group into three equal groups, padding on the right with zero if necessary.

: pad-length ( str -- n )
    length dup 3 mod [ 3 swap - + ] unless-zero ;

: three-groups ( str -- array )
    dup pad-length [ CHAR: 0 pad-tail ] [ 3 / group ] bi ;

3. Convert each segment into a two-digit hexadecimal value, shortening each segment first to eight chars from the right, padding on the left if only one character.

: hex-rgb ( array -- array' )
    [
        8 short tail*
        2 short head
        2 CHAR: 0 pad-head
    ] map ;

Putting that together, we have this word to parse “flex hex” colors (removing hash-marks from the left if present):

: flex-hex ( str -- hex )
    "#" ?head drop hex-only three-groups hex-rgb "" join ;

And, of course, some tests to verify that we handle lots of different cases:

{ "00b000" } [ "#zqbttv" flex-hex ] unit-test

{ "0f0000" } [ "f" flex-hex ] unit-test
{ "000f00" } [ "0f" flex-hex ] unit-test
{ "000f00" } [ "0f0" flex-hex ] unit-test
{ "0f0f00" } [ "0f0f" flex-hex ] unit-test
{ "0ff000" } [ "0f0f0f0" flex-hex ] unit-test

{ "ad0e0e" } [ "adamlevine" flex-hex ] unit-test
{ "000000" } [ "MrT" flex-hex ] unit-test
{ "00c000" } [ "sick" flex-hex ] unit-test
{ "c0a000" } [ "crap" flex-hex ] unit-test
{ "c00000" } [ "chucknorris" flex-hex ] unit-test

{ "6ecde0" } [
    "6db6ec49efd278cd0bc92d1e5e072d68" flex-hex
] unit-test

The code for this is on my GitHub.