1

I am figuring out how to validate hexadecimal color ("#1234a6" and "#1cf") without using regExp. Can anyone please tell me why my code is not working properly

function checkHex(input) 
{
    var i, code, len;
    // If first letter isn't "#" stop executing
    if(input.charAt(0) !== "#") return false;
     code = input.charCodeAt(i);
      for(i = 1; len = input.length, i < len; i++) {
        if(len == 3 || len == 6 ) {
          if((code > 47 && code < 58) && (code > 96 && code < 103)) {
            return true;
          }
        }
        return false;
      }
}
checkHex("#1234a6"); // returns false; which should be true;

Thank you.

2
  • 1
    Why is code = input.charCodeAt(i); outside of your loop? Commented Nov 1, 2017 at 5:12
  • 1
    Only hex format or do you want any CSS color value? Also, do you care about the #RGBA and #RRGGBBAA format? Or to put it more simply, what is the use case exactly? Commented Nov 1, 2017 at 5:25

3 Answers 3

3

No loop or charcodeat required

function checkHex(input) {
    var check, code, len;
    if(typeof input == 'string') {        // check it's a string
        if(input[0] === "#") {            // and it starts with #
            len = input.length;
            // if (len === 4 || len === 7 || len == 5 || len == 9) { // 5 and 9 for #RGBA and #RRGGBBAA
            if (len === 4 || len === 7) { // and it's 4 or 7 characters
                input = input.toLowerCase(); // convert to lower case
                // parse it as hex and output as hex with # prefix
                check = '#' + ('00000000' + parseInt(input.substr(1), 16).toString(16)).substr(1 - len);
                // check it's the same number
                return check === input;
            }
        }
    }
    // all other conditions fall thru to here
    return false;
}
console.log(checkHex("#1234a6")); // true
console.log(checkHex("1234a6")); // false
console.log(checkHex("#1234")); // false
console.log(checkHex("#12345t")); // false
console.log(checkHex("#aBc")); // true
console.log(checkHex("#000")); // true
console.log(checkHex("#00001")); // false
console.log(checkHex("#000001")); // true

Let me break down the check = line into it's constituent parts

check = '#' +                       // start with a '#'
('00000000' +                       // some leading zeros for profit
    parseInt(input.substr(1), 16)   // parse the text as a HEX integer - that's the 16 argument
    .toString(16)                   // now, back to a string, in HEX, again 16 argument does that
).substr(1 - len);                  // we take the last (len-1) characters to match the input length less 1 (the # is the first line)

To break down where your code went wrong

function checkHex(input) {
    var i, code, len;
    // If first letter isn't "#" stop executing
    if(input.charAt(0) !== "#") return false;
     // next line should be inside the loop
    code = input.charCodeAt(i);
    for(i = 1; len = input.length, i < len; i++) {
        // you should check for length being 4 or 7, and this check should be outside the loop
        if(len == 3 || len == 6 ) {
            // a value can not be between 47 and 48 AND between 96 and 103 - so this is never true
            if((code > 47 && code < 58) && (code > 96 && code < 103)) {
                // returning in a for loop exits the function, so even fixing all of the above this would return true if the first digit was valid
                return true;
            }
        }
        return false;
    }
}

to do the above loop correctly

function checkHex(input) {
    var i, code, len;

    if (input[0] === "#") {
        len = input.length
        if (len == 4 || len == 7 ) {
            input = input.toLowerCase(); // rgb hex values are valid in either upper or lower case
            for(i = 1; i < len; i++) {
                code = input.charCodeAt(i);
                // note the ! and the || in the next line
                // we want to check that the digit is NOT in 0123456789 OR abcdef
                if (!((code > 47 && code < 58) || (code > 96 && code < 103))) {
                    return false; // not a hex digit, so return false
              }
            }
            //loop has made it all the way through, so it's correct
            return true;
        }
    }
    return false;
}

console.log(checkHex("#1234a6")); // true
console.log(checkHex("1234a6")); // false
console.log(checkHex("#1234")); // false
console.log(checkHex("#12345t")); // false
console.log(checkHex("#aBc")); // true
console.log(checkHex("#000")); // true
console.log(checkHex("#00001")); // false
console.log(checkHex("#000001")); // true

Sign up to request clarification or add additional context in comments.

Comments

0

Okay so here's a simple code snippet that does that correctly without loops etc.

You'll notice that I created a lambda function in there to deal with s starting with a #

This is to allow you to expand the notion to deal with specifications like rgb(1,2,3) and rgba(4, 5, 6, 1) etc.

    isRGB = function(s) {
    
           if(typeof(s) !== "string") 
               return false;
    
           if(s[0] === '#') 
             return (function(hexStr) {
                if(hexStr.length != 3 && hexStr.length != 6)
                   return false;
                return !isNaN(Number("0x" + hexStr));                  
             })(s.substr(1));
           
           return false;
    }
    

    console.log(isRGB('#01a5'));
    console.log(isRGB('#0a5'));
    console.log(isRGB('#0a5029'));

1 Comment

Perhaps running the darn'd thing in chrome screwed me over :) it does work however using isNaN is correct! Will fix
-1

You may directly parse the value to number and check against the base 10 integer value:

function checkHex(input) {
    /*
      1193126 = 0x1234a6
      463 = 0x1cf
      1166591 = 0x11ccff
    */
    if(input.charAt(0) == '#') {
        var intNumber = Number(input.replace("#","0x"));
        return isNaN(intNumber) ? false : (intNumber == 1193126 || intNumber == 463 || intNumber == 1166591);
    } else {
        return false;
    }
}

1 Comment

The OP wants to make sure that it's a valid RGB spec, and not just a number. Although the use of the Number class is correct (vs. parseInt e.g.)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.