Alex
Alex

Reputation: 68068

How to check if a string is a valid hex color representation?

For example:

AA33FF = valid hex color

Z34FF9 = invalid hex color (has Z in it)

AA33FF11 = invalid hex color (has extra characters)

Upvotes: 182

Views: 153020

Answers (11)

abhijithvijayan
abhijithvijayan

Reputation: 931

a simple solution using web api

function isHexCode(hex) {
  const validator = new Option().style;
  validator.color = hex;

  return typeof validator.color === "string" && validator.color.length > 0;
}

isHexCode("#000"); // true
isHexCode("blah"); // false

Upvotes: 1

Royi Namir
Royi Namir

Reputation: 148744

Without transparent support:

/^#[0-9A-F]{6}$/i.test('#AABBCC')

With transparent support :

/^#[0-9A-F]{6}[0-9a-f]{0,2}$/i.test('#AABBCC80')

To elaborate:

^ -> match beginning
# -> a hash
[0-9A-F] -> any integer from 0 to 9 and any letter from A to F
{6} -> the previous group appears exactly 6 times
[0-9a-f]{0,2} -> adding support for transparent ( 00..FF)
$ -> match end
i -> ignore case

If you need support for 3-character HEX codes (no transparent supported) , use the following:

/^#([0-9A-F]{3}){1,2}$/i.test('#ABC')

The only difference here is that

 [0-9A-F]{6}

is replaced with

([0-9A-F]{3}){1,2}

This means that instead of matching exactly 6 characters, it will match exactly 3 characters, but only 1 or 2 times. Allowing ABC and AABBCC, but not ABCD

Combined solution :

var reg=/^#([0-9a-f]{3}){1,2}$/i;
console.log(reg.test('#ABC')); //true
console.log(reg.test('#AABBCC')); //true

Upvotes: 430

vsync
vsync

Reputation: 130730

To write a good validation, I started from writing the positive and negative tests, establishing a baseline for which my validation code should work by, and mixing a few of the good answers here and my own logic, I came up with this:

/^#(([0-9A-Fa-f]{2}){3,4}|[0-9A-Fa-f]{3})$/.test(hex)

http://www.regexplained.co.uk

Tests Cases:

(hopefully covering over 90% of cases)

const isValidHex = hex => /^#(([0-9A-Fa-f]{2}){3,4}|[0-9A-Fa-f]{3})$/.test(hex);

// positive tests
[
  '#ffffff',   // 6-characters, valid range
  '#ffffff99', // 9-characters, last 2 for alpha channel
  '#fff',      // 3-characters
].forEach(c => console.log(isValidHex(c), c));

console.log('\nshould fail:\n\n');

// negative tests
[
  '#invalid',   // obviously not a color
  '#f',         // 1 character is not enough
  '#ff',        // 2 characters is not enough
  '#ffff',      // 4 characters is not enough
  '#fffff',     // 5 characters is not enough
  '#fffffff',   // 7 characters is not enough
  '#ffffff999', // 9 characters are too many
  '#ggg',       // HEX is base 16, so characters beyond "F" (16) are invalid
].forEach(c => console.log(isValidHex(c), c))

Upvotes: 2

cyanking
cyanking

Reputation: 1

If ARGB is expected to be supported, the supported hexadecimal digits are 3, 4, 6, 8.

const isColor = (strColor) => {
  return /^#(([0-9A-Fa-f]{2}){3,4}|[0-9A-Fa-f]{3,4})$/.test(strColor)
}

Note that {2} should precede {3,4} to ensure that the 7-digit hexadecimal can be correctly checked as false.

Upvotes: 0

Mark Manning
Mark Manning

Reputation: 1467

I decided to try a different perspective. My rules were : 1)Arbitrarily long sequence of hex characters, 2)Usage of either "0x" or "#" at the front of a sequence, or 3)Just a hex number or string. I'm thinking back to when binhex was one of the big programs. Binhex would create really large files that could be transferred to anyplace and then made back in to whatever file it was you converted. These files would have 80 characters followed by a return. So in this function I look for returns and take them back out first. Modified the function so it looks for both the "\n" and "\r". Here is the code:

////////////////////////////////////////////////////////////////////////////////
//  isHex(). Is this a hex string/value?
//  Arguments   :   0   =   Item to test
//                  1   =   V(alue) or S(tring). Default is STRING.
////////////////////////////////////////////////////////////////////////////////
function isHex()
{
    var p = 0;
    var re1 = /(\n|\r)+/g;
    var re2 = /[\Wg-zG-Z]/;
    var re3 = /v/i;
//
//  Make sure the string is really a string.
//
    var s = arguments[0];
    if( typeof s != "string" ){ s = s.toString(); }
//
//  Check if this is a hex VALUE
//  and NOT a hex STRING.
//
    var opt = arguments[1];
    if( re3.test(opt) && (s.length % 2 > 0) ){ return "false"; }
//
//  Remove any returns. BinHex files can be megabytes in length with 80
//  column information. So we have to remove all returns first.
//
    s.replace( re1, "" );
//
//  IF they send us something with the universal "0x" or the HTML "#" on the
//  front of it - we have to FIRST move where we look at the string.
//
    if( s.substr(0,1) == "#" ){ p = 1; }
        else if( s.substr(0,2).toLowerCase() == "0x" ){ p = 2; }

   if( re2.test(s.substr(p,s.length)) ){ return "false"; }

   return "true";
}

alert("HELLO There!");
alert(isHex("abcdef"));
alert(isHex("0x83464"));
alert(isHex("#273847"));
alert(isHex("This is a test"));
alert(isHex(0x5346));

I have purposefully left the return values as strings but all you have to do is to remove the double quotes and the function will then just return TRUE or FALSE.

Upvotes: 0

fflorent
fflorent

Reputation: 1656

// regular function
function isHexColor (hex) {
  return typeof hex === 'string'
      && hex.length === 6
      && !isNaN(Number('0x' + hex))
}

// or as arrow function (ES6+)
isHexColor = hex => typeof hex === 'string' && hex.length === 6 && !isNaN(Number('0x' + hex))

console.log(isHexColor('AABBCC'))   // true
console.log(isHexColor('AABBCC11')) // false
console.log(isHexColor('XXBBCC'))   // false
console.log(isHexColor('AAXXCC'))   // false

This answer used to throw false positives because instead of Number('0x' + hex), it used parseInt(hex, 16).
parseInt() will parse from the beginning of the string until it reaches a character that isn't included in the radix (16). This means it could parse strings like 'AAXXCC', because it starts with 'AA'.

Number(), on the other hand, will only parse if the whole string matches the radix. Now, Number() doesn't take a radix parameter, but luckily, you can prefix number literals to get a number in other radii.

Here's a table for clarification:

╭─────────────┬────────────┬────────┬───────────────────╮
│ Radix       │ Characters │ Prefix │ Will output 27    │
╞═════════════╪════════════╪════════╪═══════════════════╡
│ Binary      │ 0-1        │ 0b     │ Number('0b11011') │
│ Octal       │ 0-7        │ 0o     │ Number('0o33')    │
│ Decimal     │ 0-9        │ -      │ -                 │
│ Hexadecimal │ 0-9A-F     │ 0x     │ Number('0x1b')    │
╰─────────────┴────────────┴────────┴───────────────────╯

Upvotes: 44

rotato poti
rotato poti

Reputation: 131

Add a length check to make sure that you don't get a false positive

function isValidHex(testNum){
  let validHex = false;
  let numLength = testNum.length;
  let parsedNum = parseInt(testNum, 16);
  if(!isNan(parsedNum) && parsedNum.length===numLength){
     validHex = true;
  }
  return validHex;

}

Upvotes: 0

Mohit Dhawan
Mohit Dhawan

Reputation: 543

If you are trying to use it in HTML Try using this pattern Directly :

 pattern="^#+([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$"

like

<input id="hex" type="text" pattern="^#+([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$" />

It will give a validation to match the requested format.

Upvotes: 6

Dustin Poissant
Dustin Poissant

Reputation: 3428

function validColor(color){
  var $div = $("<div>");
  $div.css("border", "1px solid "+color);
  return ($div.css("border-color")!="")
}

https://gist.github.com/dustinpoissant/22ce25c9e536bb2c5a2a363601ba261c

Note: This requires jQuery

This works for ALL color types not just hex values. It also does not append unnecessary elements to the DOM tree.

Upvotes: 1

Abacus
Abacus

Reputation: 2119

If you need a function to tell you if a color is valid, you might as well have it give you something useful -- the computed values of that color -- and return null when it is not a valid color. Here's my stab at a compatible (Chrome54 & MSIE11) function to get the RGBA values of a "color" in any of the formats --be it 'green', or '#FFF', or '#89abcd', or 'rgb(0,0,128)', or 'rgba( 0, 128, 255, 0.5)'.

/* getRGBA:
  Get the RGBA values of a color.
  If input is not a color, returns NULL, else returns an array of 4 values:
   red (0-255), green (0-255), blue (0-255), alpha (0-1)
*/
function getRGBA(value) {
  // get/create a 0 pixel element at the end of the document, to use to test properties against the client browser
  var e = document.getElementById('test_style_element');
  if (e == null) {
    e = document.createElement('span');
    e.id = 'test_style_element';
    e.style.width = 0;
    e.style.height = 0;
    e.style.borderWidth = 0;
    document.body.appendChild(e);
  }

  // use the browser to get the computed value of the input
  e.style.borderColor = '';
  e.style.borderColor = value;
  if (e.style.borderColor == '') return null;
  var computedStyle = window.getComputedStyle(e);
  var c
  if (typeof computedStyle.borderBottomColor != 'undefined') {
    // as always, MSIE has to make life difficult
    c = window.getComputedStyle(e).borderBottomColor;
  } else {
    c = window.getComputedStyle(e).borderColor;
  }
  var numbersAndCommas = c.replace(new RegExp('[^0-9.,]+','g'),'');
  var values = numbersAndCommas.split(',');
  for (var i = 0; i < values.length; i++)
    values[i] = Number(values[i]);
  if (values.length == 3) values.push(1);
  return values;
}

Upvotes: 1

Terry Prothero
Terry Prothero

Reputation: 121

This can be a complicated problem. After several attempts I came up with a fairly clean solution. Let the browswer do the the work for you.

Step 1: Create a div with border-style set to none. The div can be positioned off screen or it can be any div on your page that doesn't use the borders.

Step 2: Set the border color to an empty string. The code might look something like this:

e=document.getElementbyId('mydiv');
e.style.borderColor="";

Step 3: Set the border color to the color you aren't sure about.

e.style.borderColor=testcol;

Step 4: Check to see if the color actually got changed. If testcol is invalid, no change will occur.

col2=e.style.borderColor;
if(col2.length==0) {alert("Bad Color!");}

Step 5: Clean up after yourself by setting the color back to an empty string.

e.style.borderColor="";

The Div:

<div id="mydiv" style="border-style:none; position:absolute; left:-9999px; top:-9999px;"></div>

Now the JavaScript function:

function GoodColor(color)
{
   var color2="";
   var result=true;
   var e=document.getElementById('mydiv');
   e.style.borderColor="";
   e.style.borderColor=color;
   color2=e.style.borderColor;
   if (color2.length==0){result=false;}
   e.style.borderColor="";
   return result;
}

In this case, the function is returning a true/false answer to the question, the other option is to have it return a valid color value. Your original color value, the value from borderColor or an empty string in place of invalid colors.

Upvotes: 8

Related Questions