I am presented with two 32-bit integers which have a fixed length eight character ASCII string encoded in them.
For example, the string "HEYTHERE" is split into "HEYT" and "HERE" and each is split into four bytes to give 0x48455954 and 0x48455245 or 1212504404 and 1212502597 respectively.
What's the most efficient way of converting these two numbers back into a string in Javascript?
So far I have the following but I'm wondering if there is faster / less clumsy way:
let xx1 = [ 1212504404, 1212502597 ];
let xx1str = String.fromCharCode((xx1[0] >> 24) & 255) +
String.fromCharCode((xx1[0] >> 16) & 255) +
String.fromCharCode((xx1[0] >> 8) & 255) +
String.fromCharCode( xx1[0] & 255) +
String.fromCharCode((xx1[1] >> 24) & 255) +
String.fromCharCode((xx1[1] >> 32) & 255) +
String.fromCharCode((xx1[1] >> 8) & 255) +
String.fromCharCode( xx1[1] & 255);
I think you can have a hash table of two characters or four characters.
hash2 = { '4040': 'AA', '4041': 'AB',
'4845':'HE',
'5954':'YT',
'4845':'HE',
'5245':'RE'
}
function madDecode(num) {
return hash2[num.toString(16).substr(0, 4)]
+ hash2[num.toString(16).substr(4, 4)]
}
out.innerHTML = madDecode(0x40404041) +', '
+ madDecode(1212504404) + madDecode(1212502597)
<span id=out></span>
You can improve further by using 4 character hash. And even further to use array instead of object.
hash2 = []
function chCode(x) {
x = x.toString(16)
while (x.length < 2) x = '0' + x
return x
}
function makeHash() {
for (var i = 32; i < 128; i++) {
for (var j = 32; j < 128; j++) {
hash2[parseInt(chCode(i) + chCode(j), 16)] = String.fromCharCode(i, j)
}
}
}
function arrDecode(num) {
var na = (num & 0xffff0000) >> 16,
nb = num & 0xffff
return hash2[na] + hash2[nb]
}
makeHash()
document.write(arrDecode(1212504404) + arrDecode(1212502597))
Related
https://jsfiddle.net/2L4t9saq/180/ is my fiddle
most of the code is just useless, ill just post the stuff that matters
var baseConverter = function(r, e, n) {
var o = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
if (e <= 0 || e > o.length || n <= 0 || n > o.length) return console.log("Base unallowed"), null;
var l, t = 0;
if (10 != e) {
var a = r.length;
for (l = 0; l < a; l++) {
var u, f = -1;
for (u = 0; u < o.length; u++)
if (r[l] == o[u]) {
f = 1;
break
}
if (u >= e) return console.log("Symbol unallowed in baseform"), null;
if (-1 == f) return console.log("Symbol not found"), null;
var s = a - l - 1;
t += 0 == s ? u : u * Math.pow(e, s)
}
} else t = parseInt(r);
if (10 != n) {
for (var g = []; t > 0;) {
var i = t % n;
if (i < 0 || i >= o.length) return console.log("Out of bounds error"), null;
g.push(o[i]), t = parseInt(t / n)
}
return g.reverse().toString().replace(/,/g, "")
}
return t.toString()
}
var b36torgba = function(input) {
for (var i = 1; i < (input.length / 8) + 1; i++) {
var arr = input
var r = arr.charAt[0 + (i - 1) * 8] + "" + arr.charAt[1 + (i - 1) * 8]
var g = arr.charAt[2 + (i - 1) * 8] + "" + arr.charAt[3 + (i - 1) * 8]
console.log(g.charAt[2])
var b = arr.charAt[4 + (i - 1) * 8] + "" + arr.charAt[5 + (i - 1) * 8]
console.log(b)
var a = arr.charAt[6 + (i - 1) * 8] + "" + arr.charAt[7 + (i - 1) * 8]
console.log(a)
var rrgba = baseConverter(r, 36, 10)
var grgba = baseConverter(r, 36, 10)
var brgba = baseConverter(r, 36, 10)
var argba = baseConverter(r, 36, 10)
var bigMessOfAVariable = "rgba(" + rrgba + "," + grgba + "," + brgba + "," + argba + "),"
return bigMessOfAVariable;
}
}
you can ignore the top function, all it is is a base converter script, that takes in three inputs, an input, the base its in, and the base it should be converted to: eg baseConverter(73,36,10) will output 255.
now, the problem is with my b36torgba function.
it will take in a string, which is guaranteed to have a length that is either 0, 8, or a multiple of 8, this is just standardization to make sure everything runs smoothly, without having 700 indexOf[] functions.
it takes in the input, and divides it by 8, this tells the function how many bytes it has to go through, and how many it will spit out, so a string "[7300002S7300002S]" should (divided by 8) output 2, therefore the script runs 2 iterations.
currently, it should be taking in the string, and assigning each group of 2 characters (again standard) to a specific variable, this will allow it to all be put in the end and outputted as the same string but in base 10 rgba (hence 73 being use, 73 in base 36 is 255), but before it can do any of that, it breaks when it tries to find the characters in a string, saying this syntax error:
Uncaught TypeError: Cannot read property '0' of undefined
at b36torgba ((index):40)
at window.onload ((index):55)
why does it break as soon as it tries to feed the string into my charAt()'s?
ps: i do understand that the code in its current state, if it worked, it'd only output the rgba value of the last 8 characters
Easy mistake. You're using charAt (which is a function) by doing charAt[index] (using square brackets), rather than charAt(index) (using round brackets). Fixing that up should solve your issue.
Also - you're calling the function by doing b36torgba(["7300002S7300002S"]) in your JSFiddle, and trying to do string manipulation on it. Since ["7300002S7300002S"] is an array, not a string, .charAt() won't work on it. Try calling the function by doing b36torgba("7300002S7300002S") instead.
I'm trying to convert a hexadecimal color string to a int in javascript.
The color int must be the same format as VB6. I think the bytes are not in the normal order. Ex: 255 is red (#ff0000) and 16776960 is Aqua (#00ffff)
I have a function to do the inverse: (But someone in the comments told me that it's not correct)
function VBColorToHEX(i) {
var hex = (i & 0xFF).toString(16) +
((i >> 8) & 0xFF).toString(16) +
((i >> 16) & 0xFF).toString(16) +
((i >> 24) & 0xFF).toString(16);
hex += '000000';
hex = hex.substring(0, 6);
return "#" + hex;
}
But was unable to write a function to return to my initial value.
Can you help me?
EDIT:
I corrected my original function by padding each separate colors:
function VBColorToHEX(i) {
var r = (i & 0xFF).toString(16);
var g = ((i >> 8) & 0xFF).toString(16);
var b = ((i >> 16) & 0xFF).toString(16);
r = ('0' + r).slice(-2);
g = ('0' + g).slice(-2);
b = ('0' + b).slice(-2);
return "#" + r + g + b;
}
Here's a working version of your original function, which I think will make more sense to you about how it actually works.
function VBColorToHEX(i) {
var bbggrr = ("000000" + i.toString(16)).slice(-6);
var rrggbb = bbggrr.substr(4, 2) + bbggrr.substr(2, 2) + bbggrr.substr(0, 2);
return "#" + rrggbb;
}
Then, to do the reverse, do this:
function HEXToVBColor(rrggbb) {
var bbggrr = rrggbb.substr(4, 2) + rrggbb.substr(2, 2) + rrggbb.substr(0, 2);
return parseInt(bbggrr, 16);
}
function VBColorToHEX(i) {
var hex = (i & 0xFF).toString(16) +
((i >> 8) & 0xFF).toString(16) +
((i >> 16) & 0xFF).toString(16) +
((i >> 24) & 0xFF).toString(16);
hex += '000000'; // pad result
hex = hex.substring(0, 6);
return "#" + hex;
}
You're padding the result with zeroes instead of padding each color value.
For instance if i = 657930, the string hex value is something like #0A0A0A but you'll output #AAA000 instead.
Beside, if you're extracting 4 color channels you need 8 chars and not 6.
PS for the padding, see for instance this solution.
I'm trying to create a simple utility for myself to be able to convert values from rgb to hex, and vice versa. It works for the most part, except for one flaw.
If I enter a hex value like '007aff', '00' gets trimmed and the result is '7aff'. The r/g/b/ still gets the correct value, but I don't want the zeroes trimmed from the hexadecimal value. Am I doing something incorrectly?
// for anyone unfamiliar with angular
// $watch runs when the variable in quotes changes in value
// the rest is basic javascript
AngularJS:
$scope.$watch('hex', function() {
var rgb = parseInt($scope.hex, 16);
$scope.r = (rgb >> 16) & 0xFF;
$scope.g = (rgb >> 8) & 0xFF;
$scope.b = rgb & 0xFF;
$scope.rgb = 'rgb(' + $scope.r + ',' + $scope.g + ',' + $scope.b + ');';
});
$scope.$watch('r+g+b', function() {
$scope.rgb = 'rgb(' + $scope.r + ',' + $scope.g + ',' + $scope.b + ');';
$scope.hex = parseInt($scope.r << 16 | $scope.g << 8 | $scope.b).toString(16);
});
Here is a sample Plunker:
The 00 aren't directly trimmed. When your convert the rgb number to a string, you don't format it with leading zeros.
Try this to format with leading zeros:
var value = parseInt($scope.r << 16 | $scope.g << 8 | $scope.b);
$scope.hex = ('000000' + value.toString(16)).slice(-6);
After:
$scope.hex = parseInt($scope.r << 16 | $scope.g << 8 | $scope.b).toString(16);
add the following lines:
var len = $scope.hex.length;
for ( var i = 0 ; i < 6 - len ; i++ ) {
$scope.hex = '0' + $scope.hex;
}
I am trying the solutions in this thread: RGB to Hex and Hex to RGB without luck:
function rgbToHex(my_color) {
r = my_color.r;
g = my_color.g;
b = my_color.b;
return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
}
When I call the above with the following:
my_color= {r: 51, g: 51, b: 9.180000000000003}
I get:
#333309.2e147ae
which doesn't seem right. Considering how my input is formatted, am I supposed to pass values in a different way?
Your function only works for integer values now, so that if there are float numbers in the color object the return is not doing its job properly.
I personal recommend using the built in function for javascript to return integer values from any given value.
The function is parseInt()
In your case the code would change from
function rgbToHex(my_color) {
r = my_color.r;
g = my_color.g;
b = my_color.b;
return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
}
to
function rgbToHex(my_color) {
r = parseInt(my_color.r);
g = parseInt(my_color.g);
b = parseInt(my_color.b);
return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
}
You may trim out float point values for the function to work properly.. You could use this:
function rgbToHex(my_color) {
r = Math.floor(my_color.r);
g = Math.floor(my_color.g);
b = Math.floor(my_color.b);
return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
}
I'm writing a chat-server in node.js, and I want to store connected users IP-addresses in a mysql database as (unsigned) integers.
I have written a javascript method to convert an ip-address as string to an integer. I get some strange results however.
Here is my code:
function ipToInt(ip) {
var parts = ip.split(".");
var res = 0;
res += parseInt(parts[0], 10) << 24;
res += parseInt(parts[1], 10) << 16;
res += parseInt(parts[2], 10) << 8;
res += parseInt(parts[3], 10);
return res;
}
When I run call the method as ipToInt("192.168.2.44"); the result I get is -1062731220.
It seems like an overflow has occurred, which is strange, because the expected output (3232236076) is inside the number range in javascript (2^52).
When I inspect -1062731220 in binary form, I can see the 3232236076 is preserved, but filled with leading 1's.
I'm not sure, but I think the problem is with signed vs. unsigned integers.
Can any of you explain what is going on?
And possibly how to parse -1062731220 back to an string ip?
Why is the converted IP negative?
It's NOT an overflow. The first part of your IP address is 192 which converts to 11000000 in binary. You then shift that all the way to the left. When there is a 1 in the leftmost position of a 32 bit number, it's negative.
How do you convert back to a string?
Do the same thing you did to convert from a string but in reverse. Shift right (and mask)!
function intToIP(int) {
var part1 = int & 255;
var part2 = ((int >> 8) & 255);
var part3 = ((int >> 16) & 255);
var part4 = ((int >> 24) & 255);
return part4 + "." + part3 + "." + part2 + "." + part1;
}
Why reinvent the wheel? From Google:
OR, you can use what I found here:
http://javascript.about.com/library/blipconvert.htm
function dot2num(dot)
{
var d = dot.split('.');
return ((((((+d[0])*256)+(+d[1]))*256)+(+d[2]))*256)+(+d[3]);
}
function num2dot(num)
{
var d = num%256;
for (var i = 3; i > 0; i--)
{
num = Math.floor(num/256);
d = num%256 + '.' + d;
}
return d;
}
The result of the "<<" operator is always a signed, 32-bit integer, as per the spec.
When you shift back, use ">>>" to do an unsigned right shift.
You might also find this pattern useful:
ip.toLong = function toInt(ip){
var ipl=0;
ip.split('.').forEach(function( octet ) {
ipl<<=8;
ipl+=parseInt(octet);
});
return(ipl >>>0);
};
ip.fromLong = function fromInt(ipl){
return ( (ipl>>>24) +'.' +
(ipl>>16 & 255) +'.' +
(ipl>>8 & 255) +'.' +
(ipl & 255) );
};
If you're using something like node.js where you can add functionality through something like Npm then you can simply do:
npm install ip
To get that functionality from the source which is here:
https://github.com/indutny/node-ip/blob/master/lib/ip.js
You will also get a bunch of other IP utility functions with that.
You shifted left to get the original number - which is just 4 sets of bits regardless of the sign.
Shift right to get back to the IP. Doesn't matter what the sign is.
const ip2int = (x) => (x.split('.').reduce((a, v) => ((a << 8) + (+v)), 0) >>> 0);
One-Liner:
const ipToLong = ip => ip.split('.').map(parseFloat).reduce((total, part) => total * 256 + part);
Use this
function num2string(ip) {
return [24,16,8,0].map(n => (ip >> n) & 0xff).join(".")
}
function string2num(ip) {
return ip.split(".").reduce((sum,x,i) => sum + (x << 8*(3-i)), 0)
}
IP Addresses in the V4 space are unsigned 32 bit numbers, hence the IP address of FF.FF.FF.FF is 2^32 and cannot be greater then that number. Please see:
This stack overflow article on the same subject
To turn that number back into an IP address you must break the number down into its 4 parts since each byte is one octet of the address so convert the number to hex and then parse out each pair. You may or may not have to add a leading zero for the first octet.
Additionally you may have to deal with byte order of the integer ( endien issues ) but since most systems are intel based these days you might not have to deal with that.
var aaa = Number("0b"+ "192.168.2.44".split(".").map(
function(dec){
return ("00000000" + Number(dec).toString(2)).slice(-8);
}).join(""));
aaa.toString(2).match(/.{1,8}/g).map(
function(bin){
return Number("0b"+bin);
}).join(".");
I revised Evan's final answer a bit, particularly dot2num. It functions the same but might be more readable and is marginally slower.
function ip2num(ip) {
var parts = ip.split('.');
var num = 0;
num += d[0] * Math.pow(2, 24);
num += d[1] * Math.pow(2, 16);
num += d[2] * Math.pow(2, 8);
num += d[3];
return num;
}
function num2ip(num) {
var ip = num % 256;
for (var i=3; i > 0; i--) {
num = Math.floor(num / 256);
ip = num % 256 + '.' + ip;
}
return ip;
}
Try this solution, it might help:
function IpToInteger(ipAddr)
{
var parts = ipAddr.split('.');
return (((parts[0] ? parts[0] << 24 : 0) |
(parts[1] ? parts[1] << 16 : 0) |
(parts[2] ? parts[2] << 8 : 0) |
(parts[3])) >>> 0);
}
function IpAddressToLong(ip){
return ip.split('.').map((octet, index, array) => {
return parseInt(octet) * Math.pow(256, (array.length - index - 1));
}).reduce((prev, curr) => {
return prev + curr;
});
}
Taken from repo
function ip2num(ip) {
var d = ip.split(".");
var num = 0;
num += Number(d[0]) * Math.pow(256, 3);
num += Number(d[1]) * Math.pow(256, 2);
num += Number(d[2]) * Math.pow(256, 1);
num += Number(d[3]);
return num;
}
function num2ip(num) {
var ip = num % 256;
for (var i = 3; i > 0; i--) {
num = Math.floor(num / 256);
ip = (num % 256) + "." + ip;
}
return ip;
}
console.log(ip2num("192.168.0.1"));
console.log(num2ip(3232235521))
<h1>YOU IS WELCOME</h1>