Today I am generating the hashid as follows:
const Hashids = require('hashids');
const ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
let number = 1419856
let hash = new Hashids('Salto do Pedro', 6, ALPHABET).encode(number)
console.log("Hash:", hash, ". Number:", number, ". Size:", hash.length)
So what is printed on the console is:
[Running] node "c:\Users\pedro\Desktop\teste\testPedro.js"
Hash: YMMMMM . Number: 1419856 . Size: 6
[Done] exited with code=0 in 0.258 seconds
However, if I change the variable 'number' to number 1419857 the result is:
[Running] node "c:\Users\pedro\Desktop\teste\testPedro.js"
Hash: DRVVVVV . Number: 1419857 . Size: 7
[Done] exited with code=0 in 0.245 seconds
My doubt is:
The alphabet I am going through has 26 characters and I defined that the minimum size of the hashid would be 6 characters, the maximum hashid that I would have available with 6 characters would not be 308.915.776 (26 * 26 * 26 * 26 * 26 * 26 )?
Why in the number 1.419.857 he already increased one more character in my hashid?
Good question. This might look intimidating but I would try to make it as simple as possible by understanding the math behind the code.
The Hashids constructor takes parameter - (salt, minLength, alphabet, seps)
Salt - String value which makes your ids unique in your project
MinLength - Number value which is the minimum length of id string you need
alphabet - String value (Input string)
seps - String value to take care of curse words
With this set, it tries to create a buffer array with Salt and random characters(taken based on salt,sep,alphabet passed) and shuffles the positions of each character.
Now, the below is the code which encodes the value based on the above character array
id = []
do {
id.unshift(alphabetChars[input % alphabetChars.length])
input = Math.floor(input / alphabetChars.length)
} while (input > 0)
Let's first take example 1 -
this.salt = 'Salto do Pedro'
this.minLength = 6
input = 1419856
// alphabetChars is the array which generates based on salt,alphabet and seps. (complex operations invol
alphabetChars = ["A","X","R","N","W","G","Q","O","L","D","V","Y","K","J","E","Z","M"]
The final array is then joined by string and a lottery character (another some math operation calc) is appended at the start. This is returned as encoded string.
Let's first take example 2 -
this.salt = 'Salto do Pedro'
this.minLength = 6
input = 1419857
// alphabetChars is the array which generates based on salt,alphabet and seps. (complex operations invol
alphabetChars = ["V","R","Y","W","J","G","M","L","Z","K","O","D","E","A","Q","N","X"]
Now this is the reason why you get +1 character extra if the number changes (because it ran a loop extra). It's the min length of the alphabet array which is monitored rather than max length, so you cannot be sure that you would be getting the same length by +1 characters always.
Hope it helps. If you want to dig in more - Here's the code for the library - https://github.com/niieani/hashids.js/blob/master/dist/hashids.js#L197
Related
I'm trying to solve the following Leetcode problem:
You are given a large integer represented as an integer array digits,
where each digits[i] is the ith digit of the integer. The digits are
ordered from most significant to least significant in left-to-right
order. The large integer does not contain any leading 0's.
Increment the large integer by one and return the resulting array of
digits.
Example 1:
Input: digits = [1,2,3] Output: [1,2,4] Explanation: The array
represents the integer 123. Incrementing by one gives 123 + 1 = 124. Thus, the result should be [1,2,4].
Here's my code :
var plusOne = function(digits) {
let newDigit = digits.join('')
if (newDigit.length > 15) {
let digitLength = newDigit.length
let secondHalf = newDigit.slice(digitLength - 15, digitLength)
secondHalf = parseInt(secondHalf) + 1
secondHalf = Array.from(String(secondHalf), Number)
digits.splice(digitLength - 15, 15)
return digits.concat(secondHalf)
}
let Digit = parseInt(newDigit) + 1
const answer = Array.from(String(Digit), Number)
return answer
};
Works for many data sets. Get's the following error on the following set. Why :(
When you do parseInt(secondHalf), you're effectively dropping any leading zeros in that string, and as a result those zeros don't get included in the final array. The input digits are guaranteed not to have any leading zeros, but that doesn't mean that there won't be any leading zeros if you slice the string in the middle.
Also, even fixing that, what about input arrays that are longer than 30 characters?
Consider using a BigInt instead, it'll be a lot easier.
const plusOne = function(digits) {
const bigInt = BigInt(digits.join('')) + 1n;
return [...String(bigInt)].map(Number);
}
console.log(plusOne(
'590840235570031372488506112'.split('').map(Number)
));
I am using Math.random to create a unique value.
However , it looks like after some days , if i run the same script it produces the same value that created earlier.
Is there any way to create unique value every time when ever i run the script.
Below is my code for the random method.
var RandomNo = function (Min,Max){
return Math.floor(Math.random() * (Max - Min + 1)) + Min;
}
module.exports = RandomNo;
The best way to achieve a unique value is to use Date() as milliseconds. This increasing time representation will never repeat.
Do it this way:
var RamdomNo = new Date().getTime();
Done.
Edit
If you are bound to length restrictions, the solution above won't help you as repetition is predictable using an increasing number the shorter it gets.
Then I'd suggest the following approach:
// turn Integer into String. String length = 36
function dec2string (dec) {
return ('0' + dec.toString(36)).substr(-2);
}
// generate a 20 * 2 characters long random string
function generateId () {
var arr = new Uint8Array(20);
window.crypto.getRandomValues(arr);
// return 5 characters of this string starting from position 8.
// here one can increase the quality of randomness by varying
// the position (currently static 8) by another random number <= 35
return Array.from(arr, this.dec2string).join('').substr(8,5);
}
// Test
console.log(generateId());
This pair of methods generates a 40 characters long random string consisting of letters and digits. Then you pick a sequence of 5 consecutive characters off it.
I have an upcoming project.
I have a validation program to write, beginner's level.
I've written the code most part, but in case the user inputs the year in 2 digit form I need to convert it into 4-digit form.
Then I need to declare a new variable and extract using '.subscript' the 4-digits from the National Identification Number which is a 13 digit number.
I've written most of the code so far ( I won't post it all of it here), but the code won't execute when it reaches yearString = yearString.substring(2,4).
function cnpVal() {
var cnpString = document.getElementById('lblcnp').value; //13 digit number
var dayString = document.getElementById('txtday').value;
var monthString = document.getElementById('txtmonth').value;
var yearString = document.getElementById('txtyear').value; //2 or 4 digit number
arrayCnp = cnpString.split('');
if (yearString.length != 4) {
alert("Year format requires you to enter 4 digits");
return false;
}
else {
yearString = yearString.substring(2,4);
}
Basically I need the yearString variable declared and working for a 4 digit year, i.e. 1987.
Obviously it won't work as 1987 = ["1", "9", "8", "7"] is a 4 string array, but I don't have a string at index 4.
I hope I've made myself understood and sorry for the ignorance. I stand to be corrected.
Greets.
yearString = yearString.substring(2,4); will extract the last 2 digits from yearString. String.prototype.substring accepts a start index as the first argument and an optional end index which is not included in the extraction, so yearString.substring(2,4) will take the character at index 2 and 3, and does not include the character at index 4.
Documentation for substring is available HERE
You could also try String.prototype.substr(start, length) which takes the start index of the sub string you need as the first argument and how many characters you want to extract as the second argument.
Documentation for substr is available HERE
I have a scenario where I am trying to pick the price values in Rs from strings in Javascript as follows
The price was Rs.1000
The price was Rs 1000
The price was Rs.1000 - 5000
The price was Rs.1000 - Rs.5000
The price was Rs.50,000
The price was Rs 1,25,000 - Rs 2,45,000
Now obviously, given the input with so much variety in it, its not a good idea to make a single very long cumbersome regex expression.
Currently I have divided this task into 4 parts
Part 1
// Extracts all Rs.1000 or Rs 1000
var regex = new RegExp(/\brs\W*?(\d{1,7})\b(?![,\d])/i)
Part 2
//Extracts all Rs.1000 - 2000 or Rs 1000 - Rs 2000 and any combinations of this
regex = new RegExp(/\brs\W*?(\d{1,7})\b(?![,\d])\s*?(?:-|to)\s*?(?:\brs\b\W*?)?(\d{1,7})\b(?![,\d])/i)
I need to capture the currency values like 1000 and 2000 to store and process it.
A few questions right off the bat, my array in JS has around 3000 items. I am stuck on Part 3 and 4 that involves commas. Is this the right way to go about it.
How do I get the values in 1 stroke where commas are present
This Regex seems to capture both normal numbers and numbers with commas, and since I just want numeric values rather than have anything to do with where the commas are placed,
\brs\W*?\d.,?.\d\b
I am trying to work one step forward on this expression to include 1000 - 2000 types as well. Any ideas?
You can use a regex for this task - you have a regular pattern used to find repeated patterns in a plain text, just create the pattern dynamically. There are 2 main blocks, one that will match the prices glued to other words (so that we could skip that text) and the other will capture the prices only in valid contexts.
The whole regex looks ugly and long:
/\Brs\W*(?:\d{1,7}(?:,\d+)*)\b(?:\s*(?:-|to)\s*(?:\brs\b\W*?)?(?:\d{1,7}(?:,\d+)*)\b)?|\brs\W*(\d{1,7}(?:,\d+)*)\b(?:\s*(?:-|to)\s*(?:\brs\b\W*?)?(\d{1,7}(?:,\d+)*)\b)?/gi
However, it is clear it consists of simple and easily editable building blocks:
(\\d{1,7}(?:,\\d+)*)\\b - the number part
rs\\W*${num}(?:\\s*(?:-|to)\\s*(?:\\brs\\b\\W*?)?${num})? - the price part
NOTE that the capturing groups are made non-capturing with .replace(/\((?!\?:)/g, '(?:') further in the RegExp constructor.
See the JS demo:
const num = "(\\d{1,7}(?:,\\d+)*)\\b";
const block = `rs\\W*${num}(?:\\s*(?:-|to)\\s*(?:\\brs\\b\\W*?)?${num})?`;
const regex = RegExp(`\\B${block.replace(/\((?!\?:)/g, '(?:')}|\\b${block}`, 'ig');
const str = `The price was Rs.1000
The price was Rs 1000
The price was Rs.1000 - 5000
The price was Rs.1000 - Rs.5000
The price was Rs.50,000
The price was Rs 1,25,000 - Rs 2,45,000
The price was dummytestRs 1,2665,000 - Rs 2,45,000`;
let m;
let result = [];
while ((m = regex.exec(str)) !== null) {
if (m[2]) {
result.push([m[1].replace(/,/g, ''), m[2]]);
} else if (m[1]) {
result.push([m[1].replace(/,/g, ''), ""]);
}
}
document.body.innerHTML = "<pre>" + JSON.stringify(result, 0, 4) + "</pre>";
When I want to select the nth character, I use the charAt() method, but what's the equivalent I can use when dealing with integers instead of string values?
Use String():
var number = 132943154134;
// convert number to a string, then extract the first digit
var one = String(number).charAt(0);
// convert the first digit back to an integer
var one_as_number = Number(one);
It's a stupid solution but seems to work without converting to string.
var number = 123456789;
var pos = 4;
var digit = ~~(number/Math.pow(10,pos))- ~~(number/Math.pow(10,pos+1))*10;
You could convert the number to a string and do the same thing:
parseInt((number + '').charAt(0))
If you want an existing method, convert it to a string and use charAt.
If you want a method that avoids converting it to a string, you could play games with dividing it by 10 repeatedly to strip off enough digits from the right -- say for 123456789, if you want the 3rd-from-right digit (6), divide by 10 3 times yielding 123456, then take the result mod 10 yielding 6. If you want to start counting digits from the left, which you probably do, then you need to know how many digits (base 10) are in the entire number, which you could deduce from the log base 10 of the number... All this is unlikely to be any more efficient than just converting it to a string.
function digitAt(val, index) {
return Math.floor(
(
val / Math.pow(10, Math.floor(Math.log(Math.abs(val)) / Math.LN10)-index)
)
% 10
);
};
digitAt(123456789, 0) // => 1
digitAt(123456789, 3) // => 4
A bit messy.
Math.floor(Math.log(Math.abs(val)) / Math.LN10)
Calculates the number of digits (-1) in the number.
var num = 123456;
var secondChar = num.toString()[1]; //get the second character
var number = 123456789
function return_digit(n){
r = number.toString().split('')[n-1]*1;
return r;
}
return_digit(3); /* returns 3 */
return_digit(6); /* returns 6 */