在Javascript中从RGB字符串获取颜色组件?

49

我正在使用Javascript和Canvas制作绘画应用程序,并使用如下格式的字符串来指定所选颜色:

"rgb(255,0,0)"

因为canvas上下文的fillStyle属性接受这种格式的字符串。

但是,现在我需要从这个字符串中获取各个组件,想知道是否有一种不需要杂乱的字符串操作的方法。可能有一些内置的方式将该字符串转换为一种颜色对象,然后访问它的r、g和b组件吗?

谢谢。


1
我不知道有没有,但如果被证明是错误的,我会很感兴趣。 - David Thomas
9个回答

66

注意 - 我们都认同“正则表达式吃掉了我的大脑并踢了我的狗”的态度,但是正则表达式版本似乎更好。这只是我的看法,请自行查看。

非正则表达式方法:

var rgb = 'rgb(200, 12, 53)';

rgb = rgb.substring(4, rgb.length-1)
         .replace(/ /g, '')
         .split(',');

console.log(rgb);

http://jsfiddle.net/userdude/Fg9Ba/

Outputs:

["200", "12", "53"]

或者...一个非常简单的正则表达式:

编辑:哎呀,由于某些原因,在正则表达式中加了个 i

var rgb = 'rgb(200, 12, 53)';

rgb = rgb.replace(/[^\d,]/g, '').split(',');

console.log(rgb);

http://jsfiddle.net/userdude/Fg9Ba/2


14
很好...只需要在正则表达式中添加一个句号来处理rgba浮点值:rgb.replace(/[^\d,.]/g, '').split(',') - bob
1
@bob的评论很到位,对于一个RGBA数组,返回Array [ "255", "255", "255", "0.5" ] - ᴍᴇʜᴏᴠ
1
对于 HSL,最好也加上百分号:%:/[^\d,.%]/g - bryc
如果我们使用类似rgb(234, 789, 999, -3, 2, 0.765, -6.78)这样的格式错误输入,会发生什么情况?这个输入包含浮点数、大于255的数字、负数以及超过3个值,但它将被解析为什么都没发生。 - Ath.Bar.

23

更简单的方法...

    var rgb = 'rgb(200, 12, 53)'.match(/\d+/g);
    console.log(rgb);  

这里是输出结果:

    ["200", "12", "53"]

"简单就是美!" :)


13
如果存在 alpha 通道,比如 rgba(1,1,1,0.6),那么此方法会失败,返回 ["1", "1", "1", "0", "6"] - Lorenzo Polidori
1
真的,但是如果你只使用数组中的前三个值,你将始终获得R、G、B值。 - Dror Bar
使用 /[\d\.]+/g 处理浮点数。 - Friedrich -- Слава Україні

6

我的版本将一个HEXRGBRGBa字符串作为参数,不使用正则表达式,并返回一个包含红色、绿色和蓝色(对于RGBa还有Alpha)数字值的对象。

var RGBvalues = (function() {

    var _hex2dec = function(v) {
        return parseInt(v, 16)
    };

    var _splitHEX = function(hex) {
        var c;
        if (hex.length === 4) {
            c = (hex.replace('#','')).split('');
            return {
                r: _hex2dec((c[0] + c[0])),
                g: _hex2dec((c[1] + c[1])),
                b: _hex2dec((c[2] + c[2]))
            };
        } else {
             return {
                r: _hex2dec(hex.slice(1,3)),
                g: _hex2dec(hex.slice(3,5)),
                b: _hex2dec(hex.slice(5))
            };
        }
    };

    var _splitRGB = function(rgb) {
        var c = (rgb.slice(rgb.indexOf('(')+1, rgb.indexOf(')'))).split(',');
        var flag = false, obj;
        c = c.map(function(n,i) {
            return (i !== 3) ? parseInt(n, 10) : flag = true, parseFloat(n);
        });
        obj = {
            r: c[0],
            g: c[1],
            b: c[2]
        };
        if (flag) obj.a = c[3];
        return obj;
    };

    var color = function(col) {
        var slc = col.slice(0,1);
        if (slc === '#') {
            return _splitHEX(col);
        } else if (slc.toLowerCase() === 'r') {
            return _splitRGB(col);
        } else {
            console.log('!Ooops! RGBvalues.color('+col+') : HEX, RGB, or RGBa strings only');
        }
    };

    return {
        color: color
    };
}());

console.debug(RGBvalues.color('rgb(52, 86, 120)'));
  //-> { r: 52, g: 86, b: 120 }
console.debug(RGBvalues.color('#345678'));
  //-> { r: 52, g: 86, b: 120 }
console.debug(RGBvalues.color('rgba(52, 86, 120, 0.67)'));
  //-> { r: 52, g: 86, b: 120, a: 0.67 }
console.debug(RGBvalues.color('#357'));
  //-> { r: 51, g: 85, b: 119 }

可能对某些人有用。 :)

4

试试使用颜色库,例如xolor库:

xolor("rgb(200,100,40)").r // returns the red part

使用一个29kb的库来完成可以用¹/₆₆₃ʳᵈ的代码(一行代码)完成的任务,这种做法在很多方面都是错误的。 - ashleedawg
1
它只有13kb未压缩。经过最小化和gzip压缩后为6kb。我很抱歉建议任何人使用模块化设计,而不是自己编写容易出错的垃圾正则表达式。我当时在想什么呢? - B T

3

如果您对RGB(A)数字值感兴趣:

const [r,g,b,a] = "rgb(50,205,50)".match(/\d+/g).map(Number);

请注意,如果字符串中只有3个数字,则α未定义!


1
这不适用于基于十进制的字母值。 - KFE
1
@KFE 使用 /[\d\.]+/g 处理浮点数。 - Friedrich -- Слава Україні

1
即使您确定颜色将以rgb格式而不是rgbA、十六进制、颜色名称或hsl格式呈现,您仍然可以使用'rgb(25%,55%,100%)'。
function Rgb(rgb){
    if(!(this instanceof Rgb)) return new Rgb(rgb);
    var c= rgb.match(/\d+(\.\d+)?%?/g);
    if(c){
        c= c.map(function(itm){
            if(itm.indexOf('%')!= -1) itm= parseFloat(itm)*2.55;
            return parseInt(itm);
        });
    }
    this.r= c[0];
    this.g= c[1];
    this.b= c[2];
}

var c = Rgb('rgb(10%,25%,55%)'); alert([c.r, c.g, c.b])

注意- 如果您正在使用画布,则需要映射。

否则-

Array.prototype.map=Array.prototype.map || function(fun, scope){
        var T= this, L= T.length, A= Array(L), i= 0;
        if(typeof fun== 'function'){
            while(i<L){
                if(i in T){
                    A[i]= fun.call(scope, T[i], i, T);
                }
                ++i;
            }
            return A;
        }
    }

rgb 值中使用浮点数是不合法的,对吗?我想如果您验证了字符串,就可以测试并拒绝像 rgba 这样的其他颜色格式。 - Jared Farrish

0

一个(比较)简单的正则表达式解决方案已实现在Mozilla Fathom中,可以识别字母:

/**
 * Return the extracted [r, g, b, a] values from a string like "rgba(0, 5, 255, 0.8)",
 * and scale them to 0..1. If no alpha is specified, return undefined for it.
 */
export function rgbaFromString(str) {
    const m = str.match(/^rgba?\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)$/i);
    if (m) {
        return [m[1] / 255, m[2] / 255, m[3] / 255, m[4] === undefined ? undefined : parseFloat(m[4])];
    } else {
        throw new Error('Color ' + str + ' did not match pattern rgb[a](r, g, b[, a]).');
    }
}

0

这是一个长的但适用于RGB字符串和RGBA字符串转换为数字数组的函数。

function rgbStringToArray(rgbString){
        let arr=rgbString.replace(/ /g,'').slice(
            rgbString.indexOf("(") + 1,
            rgbString.indexOf(")")
        ).split(",");
        for(let i=0;i<arr.length;i++){
            if(arr.length-1===i && arr.length===4) 
                arr[i]=parseFloat(arr[i]); 
            else 
                arr[i]=parseInt(arr[i]);
        }
        return arr;
    }

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接