Javascript text Array Data Scrambling and Descrambling - javascript

I am looking for super fast and compact Javascript code or function to scramble and descramble text stored in Arrays.
I only want this text not readable when the user go into "View Source" mode with the browser.
There are many options like add fixed numbers to the ASCII code or do some boolean calculation on the string like shifting, reversing, change to octal, hex etc.
I need this both for text and number strings. It would be best if the scrambled code where not to complex and not with sign like ", ', #, $, &, / etc.
var c = new Array();
c[0]=new Array( "Name","Home","City","Post code","Telephone","email","Web","Id","Number","xpos","ypos");
c[1]=new Array( "John","Street 123","1234","New York","555-1450123","john#demo.com","www.demo1.com","b",59,306380,565500);
c[2]=new Array( "Poul","Street 1234","2345","New York","555-7010123","poul#demo.com","www.demo2.com","i",113,308396,635477);
c[3]=new Array( "David","Street 12345","3456","New York","555-3111123","david#demo.com","www.demo3.com","i",129,377615,581358);
var Scrambler = function(n) { return ASCII(n)+1...; }
var DeScrambler = function(n) { return ASCII(n)-1...; }
$(function() {
for (var i = 0; i < c[0].length; ++i) {
for (var j = 0; j < (c.length); ++i) {
a[j][i] = DeScrambler(c[j][i]);
}
}
});
Any good idea?

How about ROT13, ROT47, or some other substitution cipher? It's simple to implement, fast, and doesn't increase the length of the string.

If you are scramble the text the user will be able to see the data being transmitted. If you only want to use JS and make it universal perhaps have the server send that data as UTF8 bytes? Also this does not fall under encryption. Encryption and Obfuscation are not the same. I provided a link to a github file that does base and data type conversions. I assume you where looking for something like this.
https://github.com/CubanAzcuy/JSBytes/blob/master/Format.js
(All Byte to UTF8 String Operations are done as unsigned bytes)
(I agree with #mishik minify(ing) your code is one of the best ways to obfuscate)

I made this working solution to solve my problem:
There are few things in this code I would like to work out better if possible.
1) In line 33 I have to use this dirty trick ""+c[i][j]) to convert number in Array to string. But when going back the problem is number is not number anymore in my array! This is very fast but if you have any better idea without loosing the number definition then pls. let me know.
2) I am using 2 version ROT13 and ROT18. I found ROT13 one-line-code version: s.replace(/[a-zA-Z]/g,function(c){return String.fromCharCode((c<="Z"?90:122)>=(c=c.charCodeAt(0)+13)?c:c-26);}); How can I add numbers and -_# letters to those ROT13 in a simple way?
3) As you can see I am using 2D Array to store my code. Any better suggestion?
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
<script type="text/javascript">
var AscII = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789#.-";
var ROT18 = "STUVWXYZ0123456789#.-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQR";
var c = new Array();
c[0]=new Array( "Name","Home","City","Post code","Telephone","email","Web","Id","Number","xpos","ypos");
c[1]=new Array( "John","Street 123","1234","New York","438-1450123","john#demo.com","www.demo1.com","b",59,306380,565500);
c[2]=new Array( "Poul","Street 1234","2345","New York","450-7010123","poul#demo.com","www.demo2.com","i",113,308396,6354772);
c[3]=new Array( "David","Street 12345","3456","New York","451-3111123","david#demo.com","www.demo3.com","i",129,377615,581358);
$(function() {
var Normal = function() {
var txt ="";
for (var i = 0; i < c.length; ++i) {
for (var j = 0; j < c[0].length; ++j) {
txt += ""+c[i][j] + ", ";
}
txt += "<br>";
}
$("#kData").html("<b>Normal ASCII<br></b>" + txt);
};
var Convert18 = function(Div, TxtFrom, TxtTo) {
var txt ="";
for (var i = 0; i < c.length; ++i) {
for (var j = 0; j < c[0].length; ++j) {
var ktxtX = decode((""+c[i][j]), TxtFrom, TxtTo);
c[i][j] = ktxtX;
txt += ktxtX + ", ";
}
txt += "<br>";
}
$(Div).html("<b>ROT18 + Numbers + #-_<br></b>" + txt);
};
var Convert13 = function(Div) {
var txt ="";
for (var i = 0; i < c.length; ++i) {
for (var j = 0; j < c[0].length; ++j) {
var ktxtX = rot13(""+c[i][j]);
// s.replace(/[a-zA-Z]/g,function(c){return String.fromCharCode((c<="Z"?90:122)>=(c=c.charCodeAt(0)+13)?c:c-26);});
c[i][j] = ktxtX;
txt += ktxtX + ", ";
}
txt += "<br>";
}
$(Div).html("<b>ROT13<br></b>" + txt);
};
var decode = function (txt, alphabet, substitution) {
return txt.split("").map(function (c) {
if (alphabet.indexOf(c) != -1) { return substitution.charAt(alphabet.indexOf(c)); }
else { return c; }
}).join("");
};
function rot13(str) {
return str.replace(/[a-zA-Z]/g, function(c) {
return String.fromCharCode((c <= 'Z' ? 90 : 122) >= (c = c.charCodeAt(0) + 13) ? c : c - 26);
});
}
Normal();
Convert18("#kData2", AscII, ROT18);
Convert18("#kData3", ROT18, AscII);
Convert13("#kData4");
Convert13("#kData5");
$("#kData6").html("Finised - j:" + c[0].length + " - i:" + c.length);
});
</script>
</head>
<body>
<div id="kData"></div>
<div id="kData2"></div>
<div id="kData3"></div>
<div id="kData4"></div>
<div id="kData5"></div>
<div id="kData6"></div>
</body>
</html>
I put copy of the code on http://jsfiddle.net/kpsphoto/b7MaQ/

Related

“str.fromCharCode is not a function”

Im getting the following errors:
str.fromCharCode is not a function
newStr.push is not a function
I have no clue why I’m getting those errors tbh. I might be using methods the wrong way
function rot13(str) {
var newStr = str;
for (i = 0; i < str.length; i++) {
str.fromCharCode(str[i] - 13);
newStr.push(i);
}
return newStr;
}
// Change the inputs below to test
console.log(
rot13("SERR PBQR PNZC")
)
You could try something like:
function rot13(str) {
var newStr = [];
for(i = 0; i < str.length; i++){
let x = String.fromCharCode(str[i].charCodeAt()-13);
newStr.push(x);
}
return newStr.join("");
}
It is String.fromCharCode, not myString.fromCharCode
Lastly you want charCodeAt to subtract from
Also you cannot push a char to a string. push is an Array method
function rot13(str) {
var newStr = []; // using an array - you can use += to concatenate to string
for (i = 0; i < str.length; i++) {
// I suggest you do not convert the space.
// Here I converted it to another type of space but you can use " " if you want
var x = str[i] == " " ? "\u2005":String.fromCharCode(str[i].charCodeAt(0) - 13);
newStr.push(x);
}
return newStr.join("");
}
// Change the inputs below to test
console.log(
rot13("SERR PBQR PNZC")
)

Perform a merge on two strings

I'm trying to build a collaborative doc editor and implement operational transformation. Imagine we have a string that is manipulated simultaneously by 2 users. They can only add characters, not remove them. We want to incorporate both of their changes.
The original string is: catspider
The first user does this: cat<span id>spider</span>
The second user does this: c<span id>atspi</span>der
I'm trying to write a function that will produce: c<span id>at<span id>spi</span>der</span>
The function I've written is close, but it produces c<span id>at<span i</span>d>spider</span> codepen here
String.prototype.splice = function(start, newSubStr) {
return this.slice(0, start) + newSubStr + this.slice(start);
};
function merge(saved, working, requested) {
if (!saved || !working || !requested) {
return false;
}
var diffSavedWorking = createDiff(working, saved);
var diffRequestedWorking = createDiff(working, requested);
var newStr = working;
for (var i = 0; i < Math.max(diffRequestedWorking.length, diffSavedWorking.length); i++) {
//splice does an insert `before` -- we will assume that the saved document characters
//should always appear before the requested document characters in this merger operation
//so we first insert requested and then saved, which means that the final string will have the
//original characters first.
if (diffRequestedWorking[i]) {
newStr = newStr.splice(i, diffRequestedWorking[i]);
//we need to update the merge arrays by the number of
//inserted characters.
var length = diffRequestedWorking[i].length;
insertNatX(diffSavedWorking, length, i + 1);
insertNatX(diffRequestedWorking, length, i + 1);
}
if (diffSavedWorking[i]) {
newStr = newStr.splice(i, diffSavedWorking[i]);
//we need to update the merge arrays by the number of
//inserted characters.
var length = diffSavedWorking[i].length;
insertNatX(diffSavedWorking, length, i + 1);
insertNatX(diffRequestedWorking, length, i + 1);
}
}
return newStr;
}
//arr1 should be the shorter array.
//returns inserted characters at their
//insertion index.
function createDiff(arr1, arr2) {
var diff = [];
var j = 0;
for (var i = 0; i < arr1.length; i++) {
diff[i] = "";
while (arr2[j] !== arr1[i]) {
diff[i] += arr2[j];
j++;
}
j++;
}
var remainder = arr2.substr(j);
if (remainder) diff[i] = remainder;
return diff;
}
function insertNatX(arr, length, pos) {
for (var j = 0; j < length; j++) {
arr.splice(pos, 0, "");
}
}
var saved = 'cat<span id>spider</span>';
var working = 'catspider';
var requested = 'c<span id>atspi</span>der';
console.log(merge(saved, working, requested));
Would appreciate any thoughts on a better / simpler way to achieve this.

Need for/while/do while loops to repeat asterisks

I have this problem, to repeat 30 asterisks for 3 lines. I made this example code but it repeats 30 numbers (1..30) from 1 number for first line, up to 30 numbers for the last line. So, I'd need the code to repeat 30 asterisks, for 3 lines each but not quite like within this code.
Sorry for bad elaboration.
var text = "";
var max = 30;
for(i = 0; i < max; i++)
{
for(j = 0; j <= i; j++)
{
text += (j+1)+" ";
}
text += "<br />";
}
A more re-usable solution will be to make a generic repeatString function that simply makes multiple copies of any string.
function repeatString(s, times) {
for (var i = 0, r = ''; i < times; i++) {
r += s;
}
return r;
}
var line = repeatString('*', 30) + '<br />',
content = repeatString(line, 3);
http://jsfiddle.net/611y2vmz/1/
Repeat the loop three times, like this:
for ( var i = 0; i < 3; i++ ) { // this is the line loop
for ( var j = 0; j < 30; j++ ) { //this is the asterix loop
document.write('*');
}
document.write('<br>');
}
Here's a simple demo
If you are using ES2015 (ES6) syntax you can leverage repeat function and string templating. Using those features your code will look like this
let text = (`${'*'.repeat(30)}<br/>`).repeat(3);
Here is an example of ES2015 (ES6) code
if you are using ES5 then you can do this way:
String.prototype.repeat = function(count) {
return count < 1 ? '' : new Array(count + 1).join(this);
};
var text = ('*'.repeat(30) + '<br/>').repeat(3);
Here is an example of ES5 code
You need your outer loop to iterate 3 times, and your inner loop to iterate 30 times. Each iteration of your inner loop should add an asterisk (instead of adding j+1 like you are doing now). This will produce 3 rows of 30 asterisks.
var TEXT = "*";
var LINE_SEPARATOR = "<br/>";
var TEXT_COUNT = 30;
var LINE_COUNT = 3;
var output = "";
for (line = 1; line <= LINE_COUNT; ++line) {
for (text = 1; text <= TEXT_COUNT; ++text) {
output += TEXT;
}
output += LINE_SEPARATOR;
}
document.write(output);
An alternative would be to use recursion:
function stars(num) {
return num > 0 ? stars(num - 1) + '*' : '';
}
var content = stars(30) + '<br/>' + stars(30) + '<br/>' + stars(30);
DEMO

Javascript Learnstreet Email Interpreter Alternative Solution

So I was doing this assignment on Learnstreet and for those of you who want to read a little on the question here's the link:
http://www.learnstreet.com/cg/simple/project/email_interpret#check
Long story short - you're given a email string like "local#domain.com" and you're expected to return a 2 member array that would look like ["local","domain"]. So I wrote this and am wondering how this is not correct.
function extractLocalDomain(str)
{
var text = str.trim(); //eliminates leading and trailing spaces
for(var i = 0; i < text.length; i++) {
if(text[i] == "#") {
var local = text.slice(0, i-1);
var domain = text.slice(i+1)
return [local,domain];
}
i++
}
}
You are incrementing i twice:
function extractLocalDomain(str) {
var text = str.trim();
for (var i = 0; i < text.length; i++) { // <- increment here
if (text[i] == "#") {
var local = text.slice(0, i - 1);
var domain = text.slice(i + 1)
return [local, domain];
}
i++ // <- and here agin, remove this
}
}
Instead of using a loop, you can also just use .indexOf.

JavaScript strings outside of the BMP

BMP being Basic Multilingual Plane
According to JavaScript: the Good Parts:
JavaScript was built at a time when Unicode was a 16-bit character set, so all characters in JavaScript are 16 bits wide.
This leads me to believe that JavaScript uses UCS-2 (not UTF-16!) and can only handle characters up to U+FFFF.
Further investigation confirms this:
> String.fromCharCode(0x20001);
The fromCharCode method seems to only use the lowest 16 bits when returning the Unicode character. Trying to get U+20001 (CJK unified ideograph 20001) instead returns U+0001.
Question: is it at all possible to handle post-BMP characters in JavaScript?
2011-07-31: slide twelve from Unicode Support Shootout: The Good, The Bad, & the (mostly) Ugly covers issues related to this quite well:
Depends what you mean by ‘support’. You can certainly put non-UCS-2 characters in a JS string using surrogates, and browsers will display them if they can.
But, each item in a JS string is a separate UTF-16 code unit. There is no language-level support for handling full characters: all the standard String members (length, split, slice etc) all deal with code units not characters, so will quite happily split surrogate pairs or hold invalid surrogate sequences.
If you want surrogate-aware methods, I'm afraid you're going to have to start writing them yourself! For example:
String.prototype.getCodePointLength= function() {
return this.length-this.split(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g).length+1;
};
String.fromCodePoint= function() {
var chars= Array.prototype.slice.call(arguments);
for (var i= chars.length; i-->0;) {
var n = chars[i]-0x10000;
if (n>=0)
chars.splice(i, 1, 0xD800+(n>>10), 0xDC00+(n&0x3FF));
}
return String.fromCharCode.apply(null, chars);
};
I came to the same conclusion as bobince. If you want to work with strings containing unicode characters outside of the BMP, you have to reimplement javascript's String methods. This is because javascript counts characters as each 16-bit code value. Symbols outside of the BMP need two code values to be represented. You therefore run into a case where some symbols count as two characters and some count only as one.
I've reimplemented the following methods to treat each unicode code point as a single character: .length, .charCodeAt, .fromCharCode, .charAt, .indexOf, .lastIndexOf, .splice, and .split.
You can check it out on jsfiddle: http://jsfiddle.net/Y89Du/
Here's the code without comments. I tested it, but it may still have errors. Comments are welcome.
if (!String.prototype.ucLength) {
String.prototype.ucLength = function() {
// this solution was taken from
// http://stackoverflow.com/questions/3744721/javascript-strings-outside-of-the-bmp
return this.length - this.split(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g).length + 1;
};
}
if (!String.prototype.codePointAt) {
String.prototype.codePointAt = function (ucPos) {
if (isNaN(ucPos)){
ucPos = 0;
}
var str = String(this);
var codePoint = null;
var pairFound = false;
var ucIndex = -1;
var i = 0;
while (i < str.length){
ucIndex += 1;
var code = str.charCodeAt(i);
var next = str.charCodeAt(i + 1);
pairFound = (0xD800 <= code && code <= 0xDBFF && 0xDC00 <= next && next <= 0xDFFF);
if (ucIndex == ucPos){
codePoint = pairFound ? ((code - 0xD800) * 0x400) + (next - 0xDC00) + 0x10000 : code;
break;
} else{
i += pairFound ? 2 : 1;
}
}
return codePoint;
};
}
if (!String.fromCodePoint) {
String.fromCodePoint = function () {
var strChars = [], codePoint, offset, codeValues, i;
for (i = 0; i < arguments.length; ++i) {
codePoint = arguments[i];
offset = codePoint - 0x10000;
if (codePoint > 0xFFFF){
codeValues = [0xD800 + (offset >> 10), 0xDC00 + (offset & 0x3FF)];
} else{
codeValues = [codePoint];
}
strChars.push(String.fromCharCode.apply(null, codeValues));
}
return strChars.join("");
};
}
if (!String.prototype.ucCharAt) {
String.prototype.ucCharAt = function (ucIndex) {
var str = String(this);
var codePoint = str.codePointAt(ucIndex);
var ucChar = String.fromCodePoint(codePoint);
return ucChar;
};
}
if (!String.prototype.ucIndexOf) {
String.prototype.ucIndexOf = function (searchStr, ucStart) {
if (isNaN(ucStart)){
ucStart = 0;
}
if (ucStart < 0){
ucStart = 0;
}
var str = String(this);
var strUCLength = str.ucLength();
searchStr = String(searchStr);
var ucSearchLength = searchStr.ucLength();
var i = ucStart;
while (i < strUCLength){
var ucSlice = str.ucSlice(i,i+ucSearchLength);
if (ucSlice == searchStr){
return i;
}
i++;
}
return -1;
};
}
if (!String.prototype.ucLastIndexOf) {
String.prototype.ucLastIndexOf = function (searchStr, ucStart) {
var str = String(this);
var strUCLength = str.ucLength();
if (isNaN(ucStart)){
ucStart = strUCLength - 1;
}
if (ucStart >= strUCLength){
ucStart = strUCLength - 1;
}
searchStr = String(searchStr);
var ucSearchLength = searchStr.ucLength();
var i = ucStart;
while (i >= 0){
var ucSlice = str.ucSlice(i,i+ucSearchLength);
if (ucSlice == searchStr){
return i;
}
i--;
}
return -1;
};
}
if (!String.prototype.ucSlice) {
String.prototype.ucSlice = function (ucStart, ucStop) {
var str = String(this);
var strUCLength = str.ucLength();
if (isNaN(ucStart)){
ucStart = 0;
}
if (ucStart < 0){
ucStart = strUCLength + ucStart;
if (ucStart < 0){ ucStart = 0;}
}
if (typeof(ucStop) == 'undefined'){
ucStop = strUCLength - 1;
}
if (ucStop < 0){
ucStop = strUCLength + ucStop;
if (ucStop < 0){ ucStop = 0;}
}
var ucChars = [];
var i = ucStart;
while (i < ucStop){
ucChars.push(str.ucCharAt(i));
i++;
}
return ucChars.join("");
};
}
if (!String.prototype.ucSplit) {
String.prototype.ucSplit = function (delimeter, limit) {
var str = String(this);
var strUCLength = str.ucLength();
var ucChars = [];
if (delimeter == ''){
for (var i = 0; i < strUCLength; i++){
ucChars.push(str.ucCharAt(i));
}
ucChars = ucChars.slice(0, 0 + limit);
} else{
ucChars = str.split(delimeter, limit);
}
return ucChars;
};
}
More recent JavaScript engines have String.fromCodePoint.
const ideograph = String.fromCodePoint( 0x20001 ); // outside the BMP
Also a code-point iterator, which gets you the code-point length.
function countCodePoints( str )
{
const i = str[Symbol.iterator]();
let count = 0;
while( !i.next().done ) ++count;
return count;
}
console.log( ideograph.length ); // gives '2'
console.log( countCodePoints(ideograph) ); // '1'
Yes, you can. Although support to non-BMP characters directly in source documents is optional according to the ECMAScript standard, modern browsers let you use them. Naturally, the document encoding must be properly declared, and for most practical purposes you would need to use the UTF-8 encoding. Moreover, you need an editor that can handle UTF-8, and you need some input method(s); see e.g. my Full Unicode Input utility.
Using suitable tools and settings, you can write var foo = '𠀁'.
The non-BMP characters will be internally represented as surrogate pairs, so each non-BMP character counts as 2 in the string length.
Using for (c of this) instruction, one can make various computations on a string that contains non-BMP characters. For instance, to compute the string length, and to get the nth character of the string:
String.prototype.magicLength = function()
{
var c, k;
k = 0;
for (c of this) // iterate each char of this
{
k++;
}
return k;
}
String.prototype.magicCharAt = function(n)
{
var c, k;
k = 0;
for (c of this) // iterate each char of this
{
if (k == n) return c + "";
k++;
}
return "";
}
This old topic has now a simple solution in ES6:
Split characters into an array
simple version
[..."😴😄😃⛔🎠🚓🚇"] // ["😴", "😄", "😃", "⛔", "🎠", "🚓", "🚇"]
Then having each one separated you can handle them easily for most common cases.
Credit: DownGoat
Full solution
To overcome special emojis as the one in the comment, one can search for the connection charecter (char code 8205 in UTF-16) and make some modifications. Here is how:
let myStr = "👩‍👩‍👧‍👧😃𝌆"
let arr = [...myStr]
for (i = arr.length-1; i--; i>= 0) {
if (arr[i].charCodeAt(0) == 8205) { // special combination character
arr[i-1] += arr[i] + arr[i+1]; // combine them back to a single emoji
arr.splice(i, 2)
}
}
console.log(arr.length) //3
Haven't found a case where this doesn't work. Comment if you do.
To conclude
it seems that JS uses the 8205 char code to represent UCS-2 characters as a UTF-16 combinations.

Categories

Resources