将随机字符串转换为十六进制颜色

15

我的应用程序中有一个操作日志表格。我希望根据该条目的sessionID为行分配随机颜色,以帮助查看模式/分组操作。

到目前为止,我已经做了这个:

console.log(stringToColorCode('mj3bPTCbIAVoNr93me1I'));

function stringToColorCode(str) {
    return '#'+ ('000000' + (Math.random()*0xFFFFFF<<0).toString(16)).slice(-6);
}

然而我需要用我的字符串整数替换Math.random(),是否有将字符串转换为随机数且与随机字符串保持一致的技巧?


1
@GolezTrol 请查看运算符优先级:乘法运算先于位移运算,因此<<0实际上是将其强制转换为32位整数。 - SheetJS
1
(parseInt(parseInt('mj3bPTCbIAVoNr93me1I', 36).toExponential().slice(2,-4)) & 0xFFFFFF).toString(16).toUpperCase(); // "32EF01" - Paul S.
3
查看这个回答:http://stackoverflow.com/questions/13785164/js-need-a-css-color-code-based-on-a-string。他建议使用字符串的哈希码,返回'#' + md5(string).slice(0, 6)作为CSS颜色代码。 - Bumptious Q Bangwhistle
@GolezTrol 你也可以使用 |0,这是人们通常会做的事情(我认为 asm.js 也使用它来推断类型) - SheetJS
@PaulS.:请将其作为答案发布(附上一点解释),这太棒了! - Bergi
显示剩余3条评论
4个回答

21

按照要求发布为回答,如所请求

var stringHexNumber = (                       // 1
    parseInt(                                 // 2
        parseInt('mj3bPTCbIAVoNr93me1I', 36)  // 3
            .toExponential()                  // 4
            .slice(2,-5)                      // 5
    , 10) & 0xFFFFFF                          // 6
).toString(16).toUpperCase(); // "32EF01"     // 7

那么,发生了什么事情?

  1. 代码的第3行开始,将字符串'mj3bPTCbIAVoNr93me1I'转换为一个整数(Integer),记作x,使用36进制进行解释。
  2. 接下来在第4行中将x转换为指数形式的字符串,因为这个数字可能很大(本例约为8e30),所以要将其转换为标准格式。
  3. 然后,在第5行中去掉开头和结尾的部分,只留下数字,例如'8.123e+30'.slice(2, -5)变成了'12'
  4. 现在回到第2行,这次将它重新转换为十进制的整数。
  5. 然后,在第6行中使用快速位运算AND将该数字截断为范围0..16777215 (=== 0xFFFFFF),这也会将NaN转换为0
  6. 最后,在第7行中,通过将数字写成16进制并更改大小写,将其转换回我们习惯于看到的大写十六进制颜色格式。

如果您想使用此代码,您可能还需要确保最终的数字是6位,并在前面加上#,可以通过以下方式完成:

'#' + ('000000' + stringHexNumber).slice(-6); // "#32EF01"

3
对于我们这些没有立即得出这个有趣结论的人,需要澄清一些问题:我了解到36进制有一个名字叫做26进制。它是一种特殊情况,因为它可以用0-9A-Z轻松表示,因此parseInt(sessionID, 36)假设sessionID是字母数字混合的。在调用toExponential()之后,执行slice(2,-5)操作。从2开始以跳过第一个小数点,到末尾的倒数第5位结束,因为指数可能会有5个字符-最大为e+307,超过这个范围,toExponential()返回无穷大。 - p e p

10
var color_codes = {};
function stringToColorCode(str) {
    return (str in color_codes) ? color_codes[str] : (color_codes[str] = '#'+ ('000000' + (Math.random()*0xFFFFFF<<0).toString(16)).slice(-6));
}

7
这个方法效果不错,但刷新页面后会出现差异。每次加载页面时页面都会呈现不同的外观。由于问题没有明确要求在加载时保持一致,所以这个方法可能符合提问者的需求。 - Bumptious Q Bangwhistle
1
把随机十六进制数存储在一个对象中是一个简单而有效的解决方案,谢谢! - Titan

2
甜美的问题。我创建了一个全局变量,所以你可以“一致地”获取给定输入字符串的相同颜色。一旦你调用了stringToColorCode,它就只会为该字符串生成一次随机颜色。你可以依靠这个结果是一致的,因此如果你连续使用相同的字符串调用函数,它将返回相同的随机颜色。我唯一看到的缺点是,可能(但不太可能)两个不同的字符串可能被映射到相同的颜色,但如果必要的话,这可以解决。
编辑:当我第一次回答时,我没有意识到@Nirk几乎有相同的答案。为了使这个答案更加独特,请使用以下内容,这将在页面重新加载时给您一致的颜色。
console.log(stringToColorCode('mj3bPTCbIAVoNr93me1I'));

function stringToColorCode(str) {
    var sessionStoreKey = "myStringColors" + str;
    if (!sessionStorage[sessionStoreKey ]) {
        sessionStorage[sessionStoreKey] = Math.random()*0xFFFFFF<<0;       
    }

    var randomColor = sessionStorage[sessionStoreKey];

    return '#'+ randomColor;
}

你不应该使用数组来实现这个目的;顺便说一句,@Nirk 已经有了同样的解决方案 :-) - Bergi
我明白我(误导性地)将stringToRandomColorMap声明为[],但我不是在设置stringToRandomColorMap对象的属性吗?类似于这个链接中的操作:https://dev59.com/q2w05IYBdhLWcg3wuUGY。你还认为我错误地使用了数组吗?如果是这样,我想知道原因。谢谢! - p e p
数组仅适用于数字索引。阅读《认为“关联数组”有害》(http://andrewdupont.net/2006/05/18/javascript-associative-arrays-considered-harmful/),并使用对象代替(`var stringToRandomColorMap = {}`)。 - Bergi
是的,数组只能使用数字索引。我最初并不是想将其声明为数组。实际上(在调试器中快速尝试),如果我最初将对象声明为数组,那么稍后我就可以访问像.length这样的属性。有趣的是,即使我设置了myArray ["test"] = "something",myArray.length仍然为0,尽管myArray.test显然是可访问的。谢谢你指出这一点,这不是我最初认为会发生的事情,我以为myArray会停止成为一个数组,但它没有。 - p e p
1
你所做的被称为“记忆化”,一种优化技术。你可以在这里阅读更多相关信息。 - Dogoku

-1

我在后端Bean中解决了这个问题。 这段Java代码对我有效:

private void createDefaultColorFromName(final String name) {
    String md5 = "#" + md5(name).substring(0, 6);
    defaultColor = Color.decode(md5);
    int darkness = ((defaultColor.getRed() * 299) + (defaultColor.getGreen() * 587) + (defaultColor.getBlue() * 114)) / 1000;
    if (darkness > 125) {
        defaultColor = defaultColor.darker();
    }
}

我将生成的颜色稍微加深了一点,以适应白色背景...


这并没有提供问题的答案。如果您想对作者进行批评或请求澄清,请在他们的帖子下留言。 - Santosh A
@SantoshA:我刚刚为一个类似的问题写了我的解决方案!这有什么问题吗?? - Gatschet

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