Is there a way that a can encode my string Olá to Olá in JavaScript? And do this to all accented characters.
My header looks like:
Content-Type: text/html;charset=iso-8859-1
If you already have a proper string, you can do it like this:
ECMAScript ≥ 6, with Emoji support
(see: https://medium.com/#giltayar/iterating-over-emoji-characters-the-es6-way-f06e4589516)
function decimalEscape(s) {
let buffer = [];
for(let ch of s) {
if(ch.codePointAt(0) <= 127) {
buffer.push(ch);
} else {
buffer.push('&#' + ch.codePointAt(0) + ';');
}
}
return buffer.join('');
}
ECMAScript ≤ 5, without Emoji support:
function decimalEscape(s) {
var buffer = [];
for(var i = 0, f = s.length; i < f; ++i) {
if(s.charCodeAt(i) <= 127) {
buffer.push(s.charAt(i));
} else {
buffer.push('&#' + s.charCodeAt(i) + ';');
}
}
return buffer.join('');
}
Usage:
decimalEscape("Olá"); // -> returns "Olá"
If you don't have a proper JavaScript string yet (just a bunch of bytes in some kind of buffer or if the string you have is already in the wrong encoding), you will have to fix the string first, of course.
I'm working with a system that integrates a Point of Sell (POS) device, I use chrome serial to scan ports and be able to read credit card data.
The problem I'm facing is that I need to concat the LRC from a string in this format:
STX = '\002' (2 HEX) (Start of text)
LLL = Length of data (doesn't include STX or ETX but command).
Command C50 {C = A message from PC to POS, 50 the actual code that "prints" a message on POS}
ETX = '\003' (3 HEX) (End of text)
LRC = Longitudinal Redundancy Check
A message example would be as follows:
'\002014C50HELLO WORLD\003'
Here we can see 002 as STX, 014 is the length from C50 to D, and 003 as ETX.
I found some algorithms in C# like this one or this one and even this one in Java, I even saw this question that was removed from SO on Google's cache, which actually asks the same as I but had no examples or answers.
I also made this Java algorithm:
private int calculateLRC(String str) {
int result = 0;
for (int i = 0; i < str.length(); i++) {
String char1 = str.substring(i, i + 1);
char[] char2 = char1.toCharArray();
int number = char2[0];
result = result ^ number;
}
return result;
}
and tried passing it to Javascript (where I have poor knowledge)
function calculateLRC2(str) {
var result = 0;
for (var i = 0; i < str.length; i++) {
var char1 = str.substring(i, i + 1);
//var char2[] = char1.join('');
var number = char1;
result = result ^ number;
}
return result.toString();
}
and after following the Wikipedia's pseudocode I tried doing this:
function calculateLRC(str) {
var buffer = convertStringToArrayBuffer(str);
var lrc;
for (var i = 0; i < str.length; i++) {
lrc = (lrc + buffer[i]) & 0xFF;
}
lrc = ((lrc ^ 0xFF) + 1) & 0xFF;
return lrc;
}
This is how I call the above method:
var finalMessage = '\002014C50HELLO WORLD\003'
var lrc = calculateLRC(finalMessage);
console.log('lrc: ' + lrc);
finalMessage = finalMessage.concat(lrc);
console.log('finalMessage: ' + finalMessage);
However after trying all these methods, I still can't send a message to POS correctly. I have 3 days now trying to fix this thing and can't do anything more unless I finish it.
Is there anyone that knows another way to calculate LRC or what am I doing wrong here? I need it to be with Javascritpt since POS comunicates with PC through NodeJS.
Oh btw the code from convertStringToArrayBuffer is on the chrome serial documentation which is this one:
var writeSerial=function(str) {
chrome.serial.send(connectionId, convertStringToArrayBuffer(str), onSend);
}
// Convert string to ArrayBuffer
var convertStringToArrayBuffer=function(str) {
var buf=new ArrayBuffer(str.length);
var bufView=new Uint8Array(buf);
for (var i=0; i<str.length; i++) {
bufView[i]=str.charCodeAt(i);
}
return buf;
}
Edit After testing I came with this algorithm which returns a 'z' (lower case) with the following input: \002007C50HOLA\003.
function calculateLRC (str) {
var bytes = [];
var lrc = 0;
for (var i = 0; i < str.length; i++) {
bytes.push(str.charCodeAt(i));
}
for (var i = 0; i < str.length; i++) {
lrc ^= bytes[i];
console.log('lrc: ' + lrc);
//console.log('lrcString: ' + String.fromCharCode(lrc));
}
console.log('bytes: ' + bytes);
return String.fromCharCode(lrc);
}
However with some longer inputs and specialy when trying to read card data, LRC becomes sometimes a Control Character which in my case that I use them on my String, might be a problem. Is there a way to force LRC to avoid those characters? Or maybe I'm doing it wrong and that's why I'm having those characters as output.
I solved LRC issue by calculating it with the following method, after reading #Jack A.'s answer and modifying it to this one:
function calculateLRC (str) {
var bytes = [];
var lrc = 0;
for (var i = 0; i < str.length; i++) {
bytes.push(str.charCodeAt(i));
}
for (var i = 0; i < str.length; i++) {
lrc ^= bytes[i];
}
return String.fromCharCode(lrc);
}
Explanation of what it does:
1st: it converts the string received to it's ASCII equivalent (charCodeAt()).
2nd: it calculates LRC by doing a XOR operation between last calculated LRC (0 on 1st iteration) and string's ASCII for each char.
3rd: it converts from ASCII to it's equivalent chat (fromCharCode()) and returns this char to main function (or whatever function called it).
Your pseudocode-based algorithm is using addition. For the XOR version, try this:
function calculateLRC(str) {
var buffer = convertStringToArrayBuffer(str);
var lrc = 0;
for (var i = 0; i < str.length; i++) {
lrc = (lrc ^ buffer[i]) & 0xFF;
}
return lrc;
}
I think your original attempt at the XOR version was failing because you needed to get the character code. The number variable still contained a string when you did result = result ^ number, so the results were probably not what you expected.
This is a SWAG since I don't have Node.JS installed at the moment so I can't verify it will work.
Another thing I would be concerned about is character encoding. JavaScript uses UTF-16 for text, so converting any non-ASCII characters to 8-bit bytes may give unexpected results.
var hex1 = "B1C85C061C98E713DEF0E2EDDDDB432738674C9F8962F09B75E943D55F9FB39F";
var hex2 = "121B0D3327A21B8048FC7CA6FD07AACC0D8DF59B99DB098686696573E3686E6C";
var result = hex1 ^ hex2; //XOR the values
console.log(result); // outputs: 0 which does not sound good.
Any ideas how to perform XOR operations on hex values?
Bitwise operations in JavaScript only work on numeric values.
You should parseInt(hexString, 16) your hex string before. Specifically in your case this wouldn't work because your hex is too big for a number. You would have to create your own customized XOR function.
Take a look at this link: How to convert hex string into a bytes array, and a bytes array in the hex string?
The resulting bytearray will be ellegible for a manual XOR. Byte by byte. Maybe this will help: Java XOR over two arrays.
If you are on Nodejs, you could transform the hex strings to Buffers then use map to build the resulting string.
function xor(hex1, hex2) {
const buf1 = Buffer.from(hex1, 'hex');
const buf2 = Buffer.from(hex2, 'hex');
const bufResult = buf1.map((b, i) => b ^ buf2[i]);
return bufResult.toString('hex');
}
str = 'abc';
c = '';
key = 'K';
for(i=0; i<str.length; i++) {
c += String.fromCharCode(str[i].charCodeAt(0).toString(10) ^ key.charCodeAt(0).toString(10)); // XORing with letter 'K'
}
return c;
Output of string 'abc':
"*)("
You can use a function like this.
function xor(a, b) {
if (!Buffer.isBuffer(a)) a = new Buffer(a)
if (!Buffer.isBuffer(b)) b = new Buffer(b)
var res = []
if (a.length > b.length) {
for (var i = 0; i < b.length; i++) {
res.push(a[i] ^ b[i])
}
} else {
for (var i = 0; i < a.length; i++) {
res.push(a[i] ^ b[i])
}
}
return new Buffer(res);
}
Source: https://github.com/czzarr/node-bitwise-xor
Below is function that takes in 2 strings like "041234FFFFFFFFFF" and "0000000709000003" (a classic example of pin block and card block)
Expected result from the above 2 strings is "041234F8F6FFFFFC"
function bitwiseXorHexString(pinBlock1, pinBlock2) {
var result = ''
for (let index = 0; index < 16; index++) {
const temp = (parseInt(pinBlock1.charAt(index), 16) ^ parseInt(pinBlock2.charAt(index), 16)).toString(16).toUpperCase()
result += temp
}
return result
}
Note: This was made to xor 2 strings of fixed length 16. You may modify it as per your needs.
I want JavaScript to translate text in a textarea into binary code.
For example, if a user types in "TEST" into the textarea, the value "01010100 01000101 01010011 01010100" should be returned.
I would like to avoid using a switch statement to assign each character a binary code value (e.g. case "T": return "01010100) or any other similar technique.
Here's a JSFiddle to show what I mean. Is this possible in native JavaScript?
What you should do is convert every char using charCodeAt function to get the Ascii Code in decimal. Then you can convert it to Binary value using toString(2):
function convert() {
var output = document.getElementById("ti2");
var input = document.getElementById("ti1").value;
output.value = "";
for (var i = 0; i < input.length; i++) {
output.value += input[i].charCodeAt(0).toString(2) + " ";
}
}
<input id="ti1" value ="TEST"/>
<input id="ti2"/>
<button onClick="convert();">Convert!</button>
And here's a fiddle: http://jsfiddle.net/fA24Y/1/
This might be the simplest you can get:
function text2Binary(string) {
return string.split('').map(function (char) {
return char.charCodeAt(0).toString(2);
}).join(' ');
}
traverse the string
convert every character to their char code
convert the char code to binary
push it into an array and add the left 0s
return a string separated by space
Code:
function textToBin(text) {
var length = text.length,
output = [];
for (var i = 0;i < length; i++) {
var bin = text[i].charCodeAt().toString(2);
output.push(Array(8-bin.length+1).join("0") + bin);
}
return output.join(" ");
}
textToBin("!a") => "00100001 01100001"
Another way
function textToBin(text) {
return (
Array
.from(text)
.reduce((acc, char) => acc.concat(char.charCodeAt().toString(2)), [])
.map(bin => '0'.repeat(8 - bin.length) + bin )
.join(' ')
);
}
Here's a pretty generic, native implementation, that I wrote some time ago,
// ABC - a generic, native JS (A)scii(B)inary(C)onverter.
// (c) 2013 Stephan Schmitz <eyecatchup#gmail.com>
// License: MIT, http://eyecatchup.mit-license.org
// URL: https://gist.github.com/eyecatchup/6742657
var ABC = {
toAscii: function(bin) {
return bin.replace(/\s*[01]{8}\s*/g, function(bin) {
return String.fromCharCode(parseInt(bin, 2))
})
},
toBinary: function(str, spaceSeparatedOctets) {
return str.replace(/[\s\S]/g, function(str) {
str = ABC.zeroPad(str.charCodeAt().toString(2));
return !1 == spaceSeparatedOctets ? str : str + " "
})
},
zeroPad: function(num) {
return "00000000".slice(String(num).length) + num
}
};
and to be used as follows:
var binary1 = "01100110011001010110010101101100011010010110111001100111001000000110110001110101011000110110101101111001",
binary2 = "01100110 01100101 01100101 01101100 01101001 01101110 01100111 00100000 01101100 01110101 01100011 01101011 01111001",
binary1Ascii = ABC.toAscii(binary1),
binary2Ascii = ABC.toAscii(binary2);
console.log("Binary 1: " + binary1);
console.log("Binary 1 to ASCII: " + binary1Ascii);
console.log("Binary 2: " + binary2);
console.log("Binary 2 to ASCII: " + binary2Ascii);
console.log("Ascii to Binary: " + ABC.toBinary(binary1Ascii)); // default: space-separated octets
console.log("Ascii to Binary /wo spaces: " + ABC.toBinary(binary1Ascii, 0)); // 2nd parameter false to not space-separate octets
Source is on Github (gist): https://gist.github.com/eyecatchup/6742657
Hope it helps. Feel free to use for whatever you want (well, at least for whatever MIT permits).
var PADDING = "00000000"
var string = "TEST"
var resultArray = []
for (var i = 0; i < string.length; i++) {
var compact = string.charCodeAt(i).toString(2)
var padded = compact.substring(0, PADDING.length - compact.length) + compact
resultArray.push(padded)
}
console.log(resultArray.join(" "))
The other answers will work for most cases. But it's worth noting that charCodeAt() and related don't work with UTF-8 strings (that is, they throw errors if there are any characters outside the standard ASCII range). Here's a workaround.
// UTF-8 to binary
var utf8ToBin = function( s ){
s = unescape( encodeURIComponent( s ) );
var chr, i = 0, l = s.length, out = '';
for( ; i < l; i ++ ){
chr = s.charCodeAt( i ).toString( 2 );
while( chr.length % 8 != 0 ){ chr = '0' + chr; }
out += chr;
}
return out;
};
// Binary to UTF-8
var binToUtf8 = function( s ){
var i = 0, l = s.length, chr, out = '';
for( ; i < l; i += 8 ){
chr = parseInt( s.substr( i, 8 ), 2 ).toString( 16 );
out += '%' + ( ( chr.length % 2 == 0 ) ? chr : '0' + chr );
}
return decodeURIComponent( out );
};
The escape/unescape() functions are deprecated. If you need polyfills for them, you can check out the more comprehensive UTF-8 encoding example found here: http://jsfiddle.net/47zwb41o
Just a hint into the right direction
var foo = "TEST",
res = [ ];
foo.split('').forEach(function( letter ) {
var bin = letter.charCodeAt( 0 ).toString( 2 ),
padding = 8 - bin.length;
res.push( new Array( padding+1 ).join( '0' ) + bin );
});
console.log( res );
8-bit characters with leading 0
'sometext'
.split('')
.map((char) => '00'.concat(char.charCodeAt(0).toString(2)).slice(-8))
.join(' ');
If you need 6 or 7 bit, just change .slice(-8)
Thank you Majid Laissi for your answer
I made 2 functions out from your code:
the goal was to implement convertation of string to VARBINARY, BINARY and back
const stringToBinary = function(string, maxBytes) {
//for BINARY maxBytes = 255
//for VARBINARY maxBytes = 65535
let binaryOutput = '';
if (string.length > maxBytes) {
string = string.substring(0, maxBytes);
}
for (var i = 0; i < string.length; i++) {
binaryOutput += string[i].charCodeAt(0).toString(2) + ' ';
}
return binaryOutput;
};
and backward convertation:
const binaryToString = function(binary) {
const arrayOfBytes = binary.split(' ');
let stringOutput = '';
for (let i = 0; i < arrayOfBytes.length; i++) {
stringOutput += String.fromCharCode(parseInt(arrayOfBytes[i], 2));
}
return stringOutput;
};
and here is a working example: https://jsbin.com/futalidenu/edit?js,console
Provided you're working in node or a browser with BigInt support, this version cuts costs by saving the expensive string construction for the very end:
const zero = 0n
const shift = 8n
function asciiToBinary (str) {
const len = str.length
let n = zero
for (let i = 0; i < len; i++) {
n = (n << shift) + BigInt(str.charCodeAt(i))
}
return n.toString(2).padStart(len * 8, 0)
}
It's about twice as fast as the other solutions mentioned here including this simple es6+ implementation:
const toBinary = s => [...s]
.map(x => x
.codePointAt()
.toString(2)
.padStart(8,0)
)
.join('')
If you need to handle unicode characters, here's this guy:
const zero = 0n
const shift = 8n
const bigShift = 16n
const byte = 255n
function unicodeToBinary (str) {
const len = str.length
let n = zero
for (let i = 0; i < len; i++) {
const bits = BigInt(str.codePointAt(i))
n = (n << (bits > byte ? bigShift : shift)) + bits
}
const bin = n.toString(2)
return bin.padStart(8 * Math.ceil(bin.length / 8), 0)
}
this seems to be the simplified version
Array.from('abc').map((each)=>each.charCodeAt(0).toString(2)).join(" ")
This is as short as you can get. It's based on the top-rated answer but transformed to a reduce function.
"TEST".split("").reduce(function (a, b) { return a + b.charCodeAt(0).toString(2)}, "")
const textToBinary = (string) => {
return string.split('').map((char) =>
char.charCodeAt().toString(2)).join(' ');
}
console.log(textToBinary('hello world'))
var UTF8ToBin=function(f){for(var a,c=0,d=(f=unescape(encodeURIComponent(f))).length,b="";c<d;c++){for(a=f.charCodeAt(c).toString(2);a.length%8!=0;){a="0"+a}b+=a}return b},binToUTF8=function(f){for(var a,c=0,d=f.length,b="";c<d;c+=8){b+="%"+((a=parseInt(f.substr(c,8),2).toString(16)).length%2==0?a:"0"+a)}return decodeURIComponent(b)};
This is a small minified JavaScript Code to convert UTF8 to Binary and Vice versa.
This is a solution for UTF-8-based textual binary representation. It leverages TextEncoder, which encodes a string to its UTF-8 bytes.
This solution separates characters by spaces. The individual "byte-bits" of multi-byte characters are separated by a minus character (-).
// inspired by https://stackoverflow.com/a/40031979/923560
function stringToUtf8BinaryRepresentation(inputString) {
const result = Array.from(inputString).map(
char => [... new TextEncoder().encode(char)].map(
x => x.toString(2).padStart(8, '0')
).join('-')
).join(' ');
return result;
}
// ### example usage #########################
function print(inputString) {
console.log("--------------");
console.log(inputString);
console.log(stringToUtf8BinaryRepresentation(inputString));
}
// compare with https://en.wikipedia.org/wiki/UTF-8#Encoding
// compare with https://en.wikipedia.org/wiki/UTF-8#Codepage_layout
// compare with UTF-16, which JavaScript uses for strings: https://en.wikipedia.org/wiki/UTF-16#Examples
print("TEST");
print("hello world");
print("$");
print("£");
print("€");
print("한");
print("𐍈");
print("παράδειγμα");
print("🤡");
print("👨👩👧👦");
print("👩🏻🤝🧑🏿");
print("🇺🇦");
use the code: 'text'.split('').map(e=>{return e.charCodeAt(0).toString(2)}) e.g.-
const text='some text';
const output=text.split('').map(e=>{return e.charCodeAt(0).toString(2)})
Simple using Buffer
const text = "TEST";
[...Buffer.from(text).values()] // [ 84, 69, 83, 84 ]
.map(byte => byte.toString(2).padStart(8, 0)) // [ '01010100', '01000101', '01010011', '01010100' ]
.join(' ') // '01010100 01000101 01010011 01010100'
The shortest and simplest solution:
"x".charCodeAt().toString(2) // 1111000
String.charCodeAt() charCodeAt(0) returns unicode: "x".charCodeAt() // 120
Object.toString() charCodeAt().toString(2) converts unicode to binary.
For multiple string characters:
[..."Tesla"].map((i) => i.charCodeAt().toString(2)).join(" ");
// 1010100 1100101 1110011 1101100 1100001
Spread syntax (...)
[..."Tesla"] // ['T', 'e', 's', 'l', 'a']
Array.map()
[..."Tesla"].map((i) => i.charCodeAt()) // [84, 101, 115, 108, 97]
Array.join() Put a space " " after each element in the array map(i) and convert the array to string.
I'm pretty sure that you can do something like this:
Returns a STRING:
const toBinary = (str)=>{
let r = []
for (let i=0; i<str.length; i++) {
r.push(str.charCodeAt(i).toString(2));
}
return r.join("");
}
Or, as an int:
const toBinary = (str)=>{
let r = []
for (let i=0; i<str.length; i++) {
r.push(str.charCodeAt(i).toString(2));
}
return parseInt(r.join(""));
}
how to do this in Javascript or Jquery?
Please suggest in 2 steps:
1.- Word Array to Single Byte Array.
2.- Byte Array to String.
Maybe this can help:
function hex2a(hex) {
var str = '';
for (var i = 0; i < hex.length; i += 2)
str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
return str;
}
What you are trying to achieve is already implemented in CryptoJS. From the documentation:
You can convert a WordArray object to other formats by explicitly calling the toString method and passing an encoder.
var hash = CryptoJS.SHA256("Message");
alert(hash.toString(CryptoJS.enc.Base64));
alert(hash.toString(CryptoJS.enc.Hex));
Honestly I have no idea why you want to implement that yourself... But if you absolutely need to do it "manually" in the 2 steps you mentioned, you could try something like this:
function wordToByteArray(wordArray) {
var byteArray = [], word, i, j;
for (i = 0; i < wordArray.length; ++i) {
word = wordArray[i];
for (j = 3; j >= 0; --j) {
byteArray.push((word >> 8 * j) & 0xFF);
}
}
return byteArray;
}
function byteArrayToString(byteArray) {
var str = "", i;
for (i = 0; i < byteArray.length; ++i) {
str += escape(String.fromCharCode(byteArray[i]));
}
return str;
}
var hash = CryptoJS.SHA256("Message");
var byteArray = wordToByteArray(hash.words);
alert(byteArrayToString(byteArray));
The wordToByteArray function should work perfectly, but be aware that byteArrayToString will produce weird results in almost any case. I don't know much about encodings, but ASCII only uses 7 bits so you won't get ASCII chars when trying to encode an entire byte. So I added the escape function to at least be able to display all those strange chars you might get. ;)
I'd recommend you use the functions CryptoJS has already implemented or just use the byte array (without converting it to string) for your analysis.