decode numbers in an array and compare to different array - javascript

I have 2 arrays, one containing numbers and another one containing encoded numbers.
I need to match the encoded numbers to the normal numbers to find a match. The trick is that I need to decode the numbers to find a match.
let encoded = ['310254#3543129', '03254#03715P5'];
let numbers = ['3102540003543129', '0325400003715445', ...]
I have tried using a for loop with recursion for when there are multiple special characters in the string, but I am not getting the results correctly.
for (let i = 0; i < encrypted.length; i++) {
for (let j = 0; j < numbers.length; j++) {
function removeSpecialChars(referenceNumber) {
if(!/^\d*$/.test(referenceNumber)){
for (let x = 0, invalidChar = ''; invalidChar = referenceNumber.charAt(x); x++) {
let newString = '';
// which char is invalid
if (!/^\d*$/.test(invalidChar)) {
for(let y = 0; i < numbers[j].split('').length; y++){
if(numbers[j].split('')[x] === numbers[j].split('')[x + y]){
newString += numbers[j].split('')[x];
} else break;
}
return removeSpecialChars(referenceNumber.replace(invalidChar, newString));
}
}
}
return referenceNumber;
} // end function
if (removeSpecialChars(encrypted[i]) === numbers[j]) {
count++;
}
}
}
I am not sure if I am approaching this in the wrong way entirely or if I am just missing something.
Here is a fiddle to reproduce my results.
https://jsfiddle.net/6ezuwhdb/1/

it seems that there are at least 2 rules at play here (I haven't looked at the fiddle in any detail but what there is here can be easily extended):
000 is encoded with a #, and
44 is encoded with a P
I would first get a complete list of these rules together and then use regular expressions to replace all instances of the special characters with their numeric equivalents.
The regular expressions use the g modifier so that all instances of the encoded value get replaced within the string.
const encoded = ['310254#3543129', '03254#03715P5'];
const decoded = encoded.map(en => {
// replace the special characters using multiple regular expressions
let result = en;
// swap all #'s for
result = result.replace(/#/g, '000');
// swap all P's for 44
result = result.replace(/P/g, '44');
// add more rules here ...
return result;
});
console.log('Decoded numbers: ', decoded);
To then check whether the normal numbers can be found within the decoded set of numbers is fairly straight forward.
// From previous step ;o)
const decoded = [
"3102540003543129",
"0325400003715445"
];
const numbers = ['3102540003543129', '0325400003715445'];
const matchedNumbers = numbers.filter(number => {
return decoded.indexOf(number) >= 0;
});
console.log(matchedNumbers);

Related

Implement the .split method

I need to implement the .split method in my own way without using prebuilt functions. The method should receive a string divided into 2 sentences by a dot and divide them through a separator.
For example, there is this string:
'word wooord wooooooooord wooooooord. wooooooooord woooooord woooord wooooooooord', separator in this case: '. '
The result should be:
['word wooord wooooooooord wooooooord", "wooooooooord woooooord woooord wooooooooord']
I tried to implement it myself, the first problem I encountered is that the words from the string are added character by character to the new array. The second problem is that the output is still a string even though I declared an array earlier.
function split(str, splitter){
let arrSent = []
for (let i = 0; i < str.length; i++){
if (str[i] != splitter){
arrSent += str[i]
}
}
return arrSent
}
console.log(split('word wooord wooooooooord wooooooord. wooooooooord woooooord woooord wooooooooord', '. '))
Since the delimiter can have more than one character, you need a system to upfront collect a sample of characters (of the same length as the delimiter) to be then compared with the delimiter:
const split = (str, delimiter) => {
// If delimiter is empty string just return an array of characters
if (delimiter === "") return [...str];
const len = delimiter.length;
const iter = str.length - len + 1; // max needed iterations
const arr = [""]; // Prefill it with empty string
let idx = 0; // arr insertion pointer
for (let i = 0; i < iter; i++) {
// Collect len chars from str as a sample
// to compare with the delimiter:
let sample = "";
for (let x = i; x < i + len; x++) {
sample += str[x];
}
const isSplit = sample === delimiter;
const isEnded = i === iter - 1;
if (isSplit) {
i += len - 1; // Consume splitted characters
idx += 1; // Increment arr pointer
arr[idx] = ""; // Prepare the new array key as empty string
} else {
// If loop ended append the entire sample.
// Otherwise, append a single character:
arr[idx] += isEnded ? sample : str[i];
}
}
return arr
}
console.log(split("word. etc", ". "));
console.log(split("word. etc. ", ". "));
console.log(split(". word yep. . etc. ", ". "));
console.log(split("word", ". "));
console.log(split("word", "word"));
console.log(split("word", ""));
console.log(split("", ""));
above, idx (starting at 0) is used as the output's arr insertion pointer. The idx is incremented if the sample matches the delimiter. Also, if there's a match, we need to skip iterations i += len, to not include the delimiter in the output array.
To test, create many examples and right before return arr; use console.log(JSON.stringify(arr) === JSON.stringify(str.split(delimiter))); - it should return true for all the submitted tests.

How to make element in Array change its' place

I'm beginner in JS. I've tried to understand Caesar Cipher ROT13, but it was too complicated for me. So I've tried to write my own code. Here it is below:
function encrip() {
var alphabet = ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"];
var str = "Ni Hao";
var string = str.toUpperCase();
for (var i = 0; i < string.length; i++) {
for (var k = 0; k < alphabet.length; k++) {
if(string.charAt(i) == alphabet[k]) {
/* console.log(string.charAt(i) + ' ' + alphabet.indexOf(alphabet[k])); */
}
}
}
}
encrip();
But I am stuck. How to do:
1. Get value from var str and then access to var alphabet , after change each letter from var str value to next 3 from alphabet (var str each element's current position would be changed) For example: Input: Ni Hao ==> output: QL KDR
2. Create universal code, I mean, not only for changing position by 3, but when I give value '5', each element would be changed by next 5 positions from alphabet. So output can be changed when I change its' value
I hope I explained everything clearly. Thanks everyone in advance for help!!
you can use the following function to encrypt english words, the 1st parameter is the string to encrypt and the 2nd for shifting
function encryp(str,pos){
var alpha="ABCDEFGHIJKLMNOPQRSTUVWXYZ";
var strUC=str.toUpperCase();
var enc="";
for(var i=0;i<strUC.length;i++){
if(strUC.charAt(i)!=" "){
enc+=alpha.charAt((alpha.indexOf(strUC.charAt(i))+pos)%26)
}
else{
enc+=" "
}
// in your case pos=3
}
return enc;
}
console.log(encryp("NiHao",3));
You don't need two for loops to do this. Iterate over the input string and find the index of each character in the alphabet array, if found add the shift to it to get the encrypted character.
To handle overflow use the modulus operator to cycle through the array.
Also I assume that you are not going use any special symbols to do the encryption.
function encrip(string, shift) {
var alphabet = ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"];
string = string.toUpperCase();
let arr = [];
for (var i = 0; i < string.length; i++) {
let char = alphabet.indexOf(string[i]) !== -1 ? alphabet[(alphabet.indexOf(string[i]) %26) + shift] : " ";
arr.push(char);
}
let encryp = arr.join("");
console.log(encryp);
return encryp;
}
encrip("Ni Hao", 3);
First of all, instead of your inner for loop scanning the whole alphabet array, you can use the built-in function indexOf:
alphabet.indexOf('K') // returns 10
Secondly, you'll want to build up your enciphered string in a separate variable. For each letter, get the index of that letter in the alphabet, add your cipher offset parameter to that index and add the resulting letter from the alphabet to your new string. An important step is that when you add to the index of the letter, you want to make sure the resulting index is within range for the alphabet array. You can do that using the % (modulo) operator, which will wrap high values back round to the start of the array. In full:
function encipher(input, offset) {
var alphabet = ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"];
var str = input.toUpperCase();
var result = '';
for (var i = 0; i < str.length; i++) {
letterIndex = alphabet.indexOf(str.charAt(i));
if (letterIndex === -1) {
result += str[i]; // if the letter isn't found in the alphabet, add it to the result unchanged
continue;
}
cipheredIndex = (letterIndex + offset) % alphabet.length; // wrap index to length of alphabet
result += alphabet[cipheredIndex];
}
console.log(result);
}
encipher('Ni Hao', 5); // output: 'SN MFT'

How to improve performance of this Javascript/Cracking the code algorithm?

so here is the question below, with my answer to it. I know that because of the double nested for loop, the efficiency is O(n^2), so I was wondering if there were a way to improve my algorithm/function's big O.
// Design an algorithm and write code to remove the duplicate characters in a string without using any additional buffer. NOTE: One or two additional variables are fine. An extra copy of the array is not.
function removeDuplicates(str) {
let arrayString = str.split("");
let alphabetArray = [["a", 0],["b",0],["c",0],["d",0],["e",0],["f",0],["g",0],["h",0],["i",0],["j",0],["k",0],["l",0],["m",0],["n",0],["o",0],["p",0],["q",0],["r",0],["s",0],["t",0],["u",0],["v",0],["w",0],["x",0],["y",0],["z",0]]
for (let i=0; i<arrayString.length; i++) {
findCharacter(arrayString[i].toLowerCase(), alphabetArray);
}
removeCharacter(arrayString, alphabetArray);
};
function findCharacter(character, array) {
for (let i=0; i<array.length; i++) {
if (array[i][0] === character) {
array[i][1]++;
}
}
}
function removeCharacter(arrString, arrAlphabet) {
let finalString = "";
for (let i=0; i<arrString.length; i++) {
for (let j=0; j<arrAlphabet.length; j++) {
if (arrAlphabet[j][1] < 2 && arrString[i].toLowerCase() == arrAlphabet[j][0]) {
finalString += arrString[i]
}
}
}
console.log("The string with removed duplicates is:", finalString)
}
removeDuplicates("Hippotamuus")
The ASCII/Unicode character codes of all letters of the same case are consecutive. This allows for an important optimization: You can find the index of a character in the character count array from its ASCII/Unicode character code. Specifically, the index of the character c in the character count array will be c.charCodeAt(0) - 'a'.charCodeAt(0). This allows you to look up and modify the character count in the array in O(1) time, which brings the algorithm run-time down to O(n).
There's a little trick to "without using any additional buffer," although I don't see a way to improve on O(n^2) complexity without using a hash map to determine if a particular character has been seen. The trick is to traverse the input string buffer (assume it is a JavaScript array since strings in JavaScript are immutable) and overwrite the current character with the next unique character if the current character is a duplicate. Finally, mark the end of the resultant string with a null character.
Pseudocode:
i = 1
pointer = 1
while string[i]:
if not seen(string[i]):
string[pointer] = string[i]
pointer = pointer + 1
i = i + 1
mark string end at pointer
The function seen could either take O(n) time and O(1) space or O(1) time and O(|alphabet|) space if we use a hash map.
Based on your description, I'm assuming the input is a string (which is immutable in javascript) and I'm not sure what exactly does "one or two additional variables" mean so based on your implementation, I'm going to assume it's ok to use O(N) space. To improve time complexity, I think implementations differ according to different requirements for the outputted string.
Assumption1: the order of the outputted string is in the order that it appears the first time. eg. "bcabcc" -> "bca"
Suppose the length of s is N, the following implementation uses O(N) space and O(N) time.
function removeDuplicates(s) {
const set = new Set(); // use set so that insertion and lookup time is o(1)
let res = "";
for (let i = 0; i < s.length; i++) {
if (!set.has(s[i])) {
set.add(s[i]);
res += s[i];
}
}
return res;
}
Assumption2: the outputted string has to be of ascending order.
You may use quick-sort to do in-place sorting and then loop through the sorted array to add the last-seen element to result. Note that you may need to split the string into an array first. So the implementation would use O(N) space and the average time complexity would be O(NlogN)
Assumption3: the result is the smallest in lexicographical order among all possible results. eg. "bcabcc" -> "abc"
The following implementation uses O(N) space and O(N) time.
const removeDuplicates = function(s) {
const stack = []; // stack and set are in sync
const set = new Set(); // use set to make lookup faster
const lastPos = getLastPos(s);
let curVal;
let lastOnStack;
for (let i = 0; i < s.length; i++) {
curVal = s[i];
if (!set.has(curVal)) {
while(stack.length > 0 && stack[stack.length - 1] > curVal && lastPos[stack[stack.length - 1]] > i) {
set.delete(stack[stack.length - 1]);
stack.pop();
}
set.add(curVal);
stack.push(curVal);
}
}
return stack.join('');
};
const getLastPos = (s) => {
// get the last index of each unique character
const lastPosMap = {};
for (let i = 0; i < s.length; i++) {
lastPosMap[s[i]] = i;
}
return lastPosMap;
}
I was unsure what was mean't by:
...without using any additional buffer.
So I thought I would have a go at doing this in one loop, and let you tell me if it's wrong.
I have worked on the basis that the function you have provided gives the correct output, you were just looking for it to run faster. The function below gives the correct output and run's a lot faster with any large string with lots of duplication that I throw at it.
function removeDuplicates(originalString) {
let outputString = '';
let lastChar = '';
let lastCharOccurences = 1;
for (let char = 0; char < originalString.length; char++) {
outputString += originalString[char];
if (lastChar === originalString[char]) {
lastCharOccurences++;
continue;
}
if (lastCharOccurences > 1) {
outputString = outputString.slice(0, outputString.length - (lastCharOccurences + 1)) + originalString[char];
lastCharOccurences = 1;
}
lastChar = originalString[char];
}
console.log("The string with removed duplicates is:", outputString)
}
removeDuplicates("Hippotamuus")
Again, sorry if I have misunderstood the post...

put dash after every n character during input from keyboard

$('.creditCardText').keyup(function() {
var foo = $(this).val().split("-").join(""); // remove hyphens
if (foo.length > 0) {
foo = foo.match(new RegExp('.{1,4}', 'g')).join("-");
}
$(this).val(foo);
});
I found this tutorial on putting dash after every 4 character from here my question is what if the character interval is not constant like in this example it is only after every 4 what if the interval is 3 characters "-" 2 characters "-" 4 characters "-" 3 characters "-" so it would appear like this 123-12-1234-123-123.
In this case, it is more convenient to just write normal code to solve the problem:
function format(input, format, sep) {
var output = "";
var idx = 0;
for (var i = 0; i < format.length && idx < input.length; i++) {
output += input.substr(idx, format[i]);
if (idx + format[i] < input.length) output += sep;
idx += format[i];
}
output += input.substr(idx);
return output;
}
Sample usage:
function format(input, format, sep) {
var output = "";
var idx = 0;
for (var i = 0; i < format.length && idx < input.length; i++) {
output += input.substr(idx, format[i]);
if (idx + format[i] < input.length) output += sep;
idx += format[i];
}
output += input.substr(idx);
return output;
}
$('.creditCardText').keyup(function() {
var foo = $(this).val().replace(/-/g, ""); // remove hyphens
// You may want to remove all non-digits here
// var foo = $(this).val().replace(/\D/g, "");
if (foo.length > 0) {
foo = format(foo, [3, 2, 4, 3, 3], "-");
}
$(this).val(foo);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<input class="creditCardText" />
While it is possible to do partial matching and capturing with regex, the replacement has to be done with a replacement function. In the replacment function, we need to determine how many capturing group actually captures some text. Since there is no clean solution with regex, I write a more general function as shown above.
You can split it using a regular expression. In this case, I'm using a expression to check for non-spaces with interval 3-2-4-3.
The RegExp.exec will return with a "match" array, with the first element containing the actual string. After removing the first element of the match, you can then join them up with dashes.
var mystring = "123121234123"
var myRegexp = /^([^\s]{3})([^\s]{2})([^\s]{4})([^\s]{3})$/g
var match = myRegexp.exec(mystring);
if (match)
{
match.shift();
mystring = match.join("-")
console.log(mystring)
}
Per further comments, the op clarified they need a fixed interval for when to insert dashes. In that case, there are several ways to implement it; I think regular expression would probably be the worst, in other words, overkill and overly complication solution.
Some simpler options would be to create a new character array, and in a loop append character by character, adding a dash too every time you get to the index you want. This would probably be the easiest to write and grok after the fact, but a little more verbose.
Or you could convert to a character array and use an 'insert into array at index'-type function like splice() (see Insert Item into Array at a Specific Index or Inserting string at position x of another string for some examples).
Pass the input value and the indexes to append the separator, first, it will remove the existing separators then just append separators on positions indexes.
export function addSeparators(
input: string,
positions: number[],
separator: string
): string {
const inputValue = input.replace(/-/g, '').split(''); // remove existing separators and split characters into array
for (let i = 0; i < inputValue.length; i++) {
if (positions.includes(i)) inputValue.splice(i, 0, separator);
}
return inputValue.join('');
}

Word Array to String

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.

Categories

Resources