JavaScript中十六进制字符串到字节值的稳健转换
Robust conversion of hexadecimal string to byte values in JavaScript
我尝试从包含十六进制字节表示的字符串中提取字节值。该字符串还包含(未知)需要忽略的非十六进制字符(分隔符,空白格式)。
给定一个输入字符串"f5 df 45:f8 a 8 f53"
,结果将是数组[245, 223, 69, 248, 168, 245]
。请注意,字节值只输出两个十六进制数字(因此,最后一个3
被忽略)。
作为附加约束,代码需要在ecmascript 3环境中工作。
到目前为止,我一直使用这种方法:function parseHex(hex){
hex = hex.replace(/[^0-9a-fA-F]/g, '');
var i,
len = hex.length,
bin = [];
for(i = 0; i < len - 1; i += 2){
bin.push(+('0x' + hex.substring(i, i + 2)));
}
return bin;
}
然而,我觉得有可能找到一个更优雅的解决方案,所以问题是:
是否有更好的解决方案来解决这个问题(将执行得更好或用更少的代码解决问题)?
更新答案(ES3)
既然你在我最初的回答的评论中提到你仅限于ES3,那么你应该能够做到这一点:
function parseHex(string) {
// remove all non-hex characters, and then separate them into an array in groups of 2 characters
var arr = string.replace(/[^0-9a-fA-F]/g, '').match(/[0-9a-fA-F]{2}/g);
// mutate the array in-place with the correct decimal values
for(var i = 0; i<arr.length; i++) {
arr[i] = parseInt(arr[i], 16);
}
return arr;
}
parseHex('f5 df 45:f8 a 8 f53'); // => [245, 223, 69, 248, 168, 245]
它基本上会做map
所做的事情,除了它比map
具有更少的空间复杂性,因为它在原地改变数组。查看更新后的jsfiddle
上一个答案(ES5)
你可以这样做(这是一个jsbin的例子):
'f5 df 45:f8 a 8 f53'.replace(/[^0-9a-fA-F]/g, '').match(/[0-9a-fA-F]{2}/g).map(function(hex) {
return parseInt(hex, 16);
});
// => [245, 223, 69, 248, 168, 245]
你可以把它变成这样的函数:
function parseHex(string) {
return string.replace(/[^0-9a-fA-F]/g, '').match(/[0-9a-fA-F]{2}/g).map(function(hex) {
return parseInt(hex, 16);
});
}
parseHex('f5 df 45:f8 a 8 f53');
本质上是从字符串中删除非十六进制字符,然后匹配两个十六进制字符组(根据您的要求)。这个答案描述了parseInt(hex, 16)
部分(相反的是hex.toString(16)
)。
TL;DR
使用regex方法会导致更少的代码,但性能更差。非正则表达式的解决方案提供了更好的性能,但代价是代码稍微多一些。
Regex方法经过更多的研究/谷歌搜索(并看到Josh beam使用.match()
回答),我认为有几种可能的regex方法可以改进原始方法。
直接使用.match()
(不使用.replace()
),灵感来自Josh Beams的回答:
function parseHex(hex){
hex = hex.match(/['da-f]/gi);
for(var i = 0; i < hex.length - 1; i += 2){
hex[i >> 1] = +('0x' + hex[i] + hex[i + 1]);
}
hex.length = i >> 1;
return hex;
}
使用.replace()
进行迭代(受此启发):
function parseHex(hex){
var bin = [];
hex.replace(/(['da-f])[^'da-f]*(['da-f])/gi,
function(m, digit1, digit2){
bin.push(+('0x' + digit1 + digit2));
}
);
return bin;
}
使用.exec()
循环(同样受到此启发):
function parseHex(hex){
var bin = [],
regex = /(['da-f])[^'da-f]*(['da-f])/gi,
result;
while(result = regex.exec(hex)){
bin.push(+('0x' + result[1] + result[2]));
}
return bin;
}
性能和非正则表达式解决方案
在这里运行性能测试后,没有任何一种regex方法的性能明显优于原始方法。出于好奇,我尝试了一个非正则表达式的解决方案,它明显优于其他方法(代价是代码稍微多一些):
function parseHex(hex){
var bin = [], i, c, isEmpty = 1, buffer;
for(i = 0; i < hex.length; i++){
c = hex.charCodeAt(i);
if(c > 47 && c < 58 || c > 64 && c < 71 || c > 96 && c < 103){
buffer = buffer << 4 ^ (c > 64 ? c + 9 : c) & 15;
if(isEmpty ^= 1){
bin.push(buffer & 0xff);
}
}
}
return bin;
}
我可能会选择非正则表达式的方法
- 本地存储中的字符串到字节数组转换
- ember.js:转换到相同的路由会产生堆栈溢出问题
- 使用状态参数转换到不同的状态
- 将十六进制字符串转换为字节数组
- 在javascript中将声音转换为字节数组
- 如何在Ember中转换到另一个路由时调用一个方法
- EmberJS:如何从控制器转换到路由器's的操作
- 为什么我需要的库没有从ES6转换到ES5
- Ember.js处理View事件后转换到路由
- 将从jquery接收的文件转换为字节数组
- 从一个HTML转换到另一个HTML
- 在JavaScript IE8中将图像转换为字节代码
- 如何在 JSP/JavaScript 中将图像转换为字节数组
- 如何在 JavaScript 中将文件加载到字节数组中
- 转换到父具有动态段的子路径
- 余烬转换到路由模型挂钩未调用
- 如何将图像数据传递给 Controiller 并转换为字节
- 余烬转换到仅当当前路由不同时
- JavaScript中十六进制字符串到字节值的稳健转换
- 类型转换- Javascript -转换字节到字节