JavaScript - 将 24 位十六进制数转换为十进制数,加 1,然后再转换回来?
JavaScript - Convert 24 digit hexadecimal number to decimal, add 1 and then convert back?
对于 MongoDB 中的 ObjectId,我使用 24 位十六进制数。因为我需要跟踪第二个集合,所以我需要给这个十六进制数加1。
就我而言,这是我的价值
var value = "55a98f19b27585d81922ba0b"
我要找的是
var newValue = "55a98f19b25785d81922ba0c"
我试图为此创建一个函数
function hexPlusOne(hex) {
var num = (("0x" + hex) / 1) + 1;
return num.toString(16);
}
这适用于较小的十六进制数
hexPlusOne("eeefab")
=> "eeefac"
但是我的散列失败得很惨
hexPlusOne(value)
=> "55a98f19b275840000000000"
有没有更好的方法解决这个问题?
错误来自尝试首先将整个 24 位十六进制值转换为数字,因为它不适合整数范围JavaScript 可以清楚地表示2。在对 JavaScript 数字进行这种转换时,会损失一些准确性。
但是,它可以作为多个(例如两个)部分进行处理:如果由于溢出1 需要,则对右侧部分进行数学计算,然后对左侧部分进行计算。 (也可以一次处理一个数字,手动完成整个加法。)
每个块的大小可以是 12 个十六进制数字,这使得它很容易分成两半。
1 即如果右边最后的num大于0xffffffffffff,就简单的往左边结(加)1。如果没有溢出,那么左边的部分保持不变。
2 参见 What is JavaScript's highest integer value that a Number can go to without losing precision?
取值范围为2^53,但传入值为16^24 ~ (2^4)^24 ~ 2^(4*24) ~ 2^96;仍然是一个有效数字,但超出了可以明确表示的整数范围。
此外,在数字上下文中使用 parseInt(str, 16)
而不是使用 "0x" + str
来强制转换,因为它可以使意图更加明确。
此版本将 return 一个与输入字符串一样长的字符串,因此如果输入类似于 "ffffffff".
,则忽略溢出
function hexIncrement(str) {
var hex = str.match(/[0-9a-f]/gi);
var digit = hex.length;
var carry = 1;
while (digit-- && carry) {
var dec = parseInt(hex[digit], 16) + carry;
carry = Math.floor(dec / 16);
dec %= 16;
hex[digit] = dec.toString(16);
}
return(hex.join(""));
}
document.write(hexIncrement("55a98f19b27585d81922ba0b") + "<BR>");
document.write(hexIncrement("ffffffffffffffffffffffff"));
此版本可能 return 一个比输入字符串长 1 个字符的字符串,因为像 "ffffffff" 这样的输入会变成“100000000”。
function hexIncrement(str) {
var hex = str.match(/[0-9a-f]/gi);
var digit = hex.length;
var carry = 1;
while (digit-- && carry) {
var dec = parseInt(hex[digit], 16) + carry;
carry = Math.floor(dec / 16);
dec %= 16;
hex[digit] = dec.toString(16);
}
if (carry) hex.unshift("1");
return(hex.join(""));
}
document.write(hexIncrement("55a98f19b27585d81922ba0b") + "<BR>");
document.write(hexIncrement("ffffffffffffffffffffffff"));
我很好奇 user2864740 关于使用 12 位数字块的建议是否有任何优势。令我惊讶的是,尽管代码看起来更复杂,但实际上速度是原来的两倍左右。但是第一个版本也是每秒运行 500,000 次,所以你不会在现实世界中注意到它。
function hexIncrement(str) {
var result = "";
var carry = 1;
while (str.length && carry) {
var hex = str.slice(-12);
if (/^f*$/i.test(hex)) {
result = hex.replace(/f/gi, "0") + result;
carry = 1;
} else {
result = ("00000000000" + (parseInt(hex, 16) + carry).toString(16)).slice(-hex.length) + result;
carry = 0;
}
str = str.slice(0,-12);
}
return(str.toLowerCase() + (carry ? "1" : "") + result);
}
document.write(hexIncrement("55a98f19b27585d81922ba0b") + "<BR>");
document.write(hexIncrement("000000000000ffffffffffff") + "<BR>");
document.write(hexIncrement("0123456789abcdef000000000000ffffffffffff"));
对于 MongoDB 中的 ObjectId,我使用 24 位十六进制数。因为我需要跟踪第二个集合,所以我需要给这个十六进制数加1。
就我而言,这是我的价值
var value = "55a98f19b27585d81922ba0b"
我要找的是
var newValue = "55a98f19b25785d81922ba0c"
我试图为此创建一个函数
function hexPlusOne(hex) {
var num = (("0x" + hex) / 1) + 1;
return num.toString(16);
}
这适用于较小的十六进制数
hexPlusOne("eeefab")
=> "eeefac"
但是我的散列失败得很惨
hexPlusOne(value)
=> "55a98f19b275840000000000"
有没有更好的方法解决这个问题?
错误来自尝试首先将整个 24 位十六进制值转换为数字,因为它不适合整数范围JavaScript 可以清楚地表示2。在对 JavaScript 数字进行这种转换时,会损失一些准确性。
但是,它可以作为多个(例如两个)部分进行处理:如果由于溢出1 需要,则对右侧部分进行数学计算,然后对左侧部分进行计算。 (也可以一次处理一个数字,手动完成整个加法。)
每个块的大小可以是 12 个十六进制数字,这使得它很容易分成两半。
1 即如果右边最后的num大于0xffffffffffff,就简单的往左边结(加)1。如果没有溢出,那么左边的部分保持不变。
2 参见 What is JavaScript's highest integer value that a Number can go to without losing precision?
取值范围为2^53,但传入值为16^24 ~ (2^4)^24 ~ 2^(4*24) ~ 2^96;仍然是一个有效数字,但超出了可以明确表示的整数范围。
此外,在数字上下文中使用 parseInt(str, 16)
而不是使用 "0x" + str
来强制转换,因为它可以使意图更加明确。
此版本将 return 一个与输入字符串一样长的字符串,因此如果输入类似于 "ffffffff".
,则忽略溢出function hexIncrement(str) {
var hex = str.match(/[0-9a-f]/gi);
var digit = hex.length;
var carry = 1;
while (digit-- && carry) {
var dec = parseInt(hex[digit], 16) + carry;
carry = Math.floor(dec / 16);
dec %= 16;
hex[digit] = dec.toString(16);
}
return(hex.join(""));
}
document.write(hexIncrement("55a98f19b27585d81922ba0b") + "<BR>");
document.write(hexIncrement("ffffffffffffffffffffffff"));
此版本可能 return 一个比输入字符串长 1 个字符的字符串,因为像 "ffffffff" 这样的输入会变成“100000000”。
function hexIncrement(str) {
var hex = str.match(/[0-9a-f]/gi);
var digit = hex.length;
var carry = 1;
while (digit-- && carry) {
var dec = parseInt(hex[digit], 16) + carry;
carry = Math.floor(dec / 16);
dec %= 16;
hex[digit] = dec.toString(16);
}
if (carry) hex.unshift("1");
return(hex.join(""));
}
document.write(hexIncrement("55a98f19b27585d81922ba0b") + "<BR>");
document.write(hexIncrement("ffffffffffffffffffffffff"));
我很好奇 user2864740 关于使用 12 位数字块的建议是否有任何优势。令我惊讶的是,尽管代码看起来更复杂,但实际上速度是原来的两倍左右。但是第一个版本也是每秒运行 500,000 次,所以你不会在现实世界中注意到它。
function hexIncrement(str) {
var result = "";
var carry = 1;
while (str.length && carry) {
var hex = str.slice(-12);
if (/^f*$/i.test(hex)) {
result = hex.replace(/f/gi, "0") + result;
carry = 1;
} else {
result = ("00000000000" + (parseInt(hex, 16) + carry).toString(16)).slice(-hex.length) + result;
carry = 0;
}
str = str.slice(0,-12);
}
return(str.toLowerCase() + (carry ? "1" : "") + result);
}
document.write(hexIncrement("55a98f19b27585d81922ba0b") + "<BR>");
document.write(hexIncrement("000000000000ffffffffffff") + "<BR>");
document.write(hexIncrement("0123456789abcdef000000000000ffffffffffff"));