2

挑战是获取一个字符串值(在 JavaScript 中)并且:

a) 确定字符串值是否是有效的颜色表示(3 位十六进制、6 位十六进制或 rgb 值)

b) 检索有效的颜色值(例如 3 个十六进制数字、3 个十六进制对或 3 个 rgb 值)

c) 尽可能高效地执行此操作。

我有以下正则表达式,它们可以工作,但我需要使它们尽可能高效。

对于 RGB(r,g,b) 匹配,要确保 r,g & b 值是 0-255,并且只允许 r,g,b 匹配(例如输入是“255,255,255”或“255,255,255”或“RGB(255,255,255)”等)

re = /^rgb\(([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5]),\s*([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5]),\s*([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\)$|^([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5]),\s*([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5]),\s*([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])$/;

对于 6 位十六进制值(例如“FFFFFF”):

re = /^([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/;

对于 3 位十六进制值(例如“FFF”):

re = /^([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])$/;

然后,对于其中的每一个,我使用:

result = re.exec(value);
if (result) {
    // process using e.g. result[1], result[2] & result[3] as needed
}

这些是实现这一目标的最有效的正则表达式吗?还是有更好的方法,也许不使用正则表达式?

(致谢:这是解决 Stoyan 在http://www.phpied.com/rgb-color-parser-in-javascript的 RGB 颜色解析器代码中发现的无效匹配)

4

2 回答 2

0

以下应该做你想要的,轻轻测试。毫无疑问,它可以进一步减少,但我不确定它是否值得。删除了注释的代码大约有 15 行。

它取决于对forEach的支持,因此要么填充它,要么用 for 循环替换。策略是标记输入,然后处理位(就像解析器一样):

/* Accept:
**   number triplets: xxx,xxx,xxx
**   rgb values     : rgb(xxx,xxx,xxx)
**   Hex values     : xxxxxx and xxxx
**   prefixed hex   : #xxxxxx and #xxx
*/
function parseColourString(s) {

  // Tokenise input
  var m = s.match(/^\#|^rgb\(|[\d\w]+$|\d{3}/g);

  // Other variables
  var value, values;
  var valid = true, double = false;

  // If no matches, return false
  if (!m) return false;

  // If hex value
  if (m.length < 3) {
    // Get the value
    value = m[m.length-1];

    // Split into parts, either x,x,x or xx,xx,xx
    values = value.length == 3? double = true && value.split('') : value.match(/../g);

    // Convert to decimal values - if #nnn, double up on values 345 => 334455
    values.forEach(function(v,i){values[i] = parseInt(double? ''+v+v : v, 16);});

  // Otherwise it's rgb, get the values
  } else {
    values = m.length == 3? m.slice() : m.slice(1);
  }

  // Check that each value is between 0 and 255 inclusive and return the result
  values.forEach(function(v){valid = valid? v >= 0 && v <= 255 : false;});

  // If string is invalid, return false, otherwise return an array of the values
  return valid && values;
}

console.log(parseColourString('#345fff'));            // [52, 95, 255]
console.log(parseColourString('#a3b'));               // [170, 51, 187]
console.log(parseColourString('#aa33bb'));            // [170, 51, 187]
console.log(parseColourString('a3b3c3'));             // [163, 179, 195]
console.log(parseColourString('rgb(123, 123, 123)')); // ["123", "123", "123"]
console.log(parseColourString('123, 123, 123'));      // ["123", "123", "123"]
console.log(parseColourString('aeiou'));              // false
console.log(parseColourString(''));                   // false
console.log(parseColourString('rgb(123,234,345)'));   // false
于 2013-10-09T23:45:31.030 回答
0

如果任何其他解决方案失败,则应使用恕我直言的正则表达式。所以这是我的方法:

var color = "(...)";
var fetchedValue;

/**
 * @param searchString
 * @return string
 */
function getHexValue(searchString) {
    var noHash = searchString.replace("#","");
    if ((noHash.length !== 6 && noHash.length !== 3) || noHash.match(/[0-9A-Fa-f]/g).length < noHash.length) {
        return false;
    }
    return noHash;
}

/**
 * @param searchString
 * @return array
 */
function getRGBValue(searchString) {
    var ingredients = searchString.match(/\d{,3}/g);
    for (var i in ingredients) {
        if (parseInt(ingredients[i]) > 255) {
            return false;
        }
    }

    return ingredients;
}

if ('#' == color.substring(0, 1)) { // the color is in HEX
    fetchedValue = getHexValue(color);
} else {
    fetchedValue = getRGBValue(color);
}
于 2013-10-09T22:22:38.400 回答