How to read letter by letter in textfield using javascript - javascript

I want to verify a Singapore NRIC using javascript,
the formula is
1) Take for example I want to test the NRIC number S1234567. The first digit you multiply by 2, second multiply by 7, third by 6, fourth by 5, fifth by 4, sixth by 3, seventh by 2. Then you add the totals together. So,1×2+2×7+3×6+4×5+5×4+6×3+7×2=106.
2) If the first letter of the NRIC starts with T or G, add 4 to the total.
3) Then you divide the number by 11 and get the remainder. 106/11=9r7
4) You can get the alphabet depending on the IC type (the first letter in the IC) using the code below:
If the IC starts with S or T: 0=J, 1=Z, 2=I, 3=H, 4=G, 5=F, 6=E, 7=D, 8=C, 9=B, 10=A
If the IC starts with F or G: 0=X, 1=W, 2=U, 3=T, 4=R, 5=Q, 6=P, 7=N, 8=M, 9=L, 10=K
How can I read every single number to do the formula?
Thanks in advance!

Strings are arrays so you can assign variables to the letters assuming you know the string has a fixed length, which it appears so, and then create a function to evaluate the characters and do the correct thing:
var nric = 'S1234567'
var chars = {
letter: nric[0],
one: nric[1],
...
}

string.charAt(charpos)
Should do the trick.
Alternatively,
string.substr(charpos,1)
You could also do
string[charpos]
but the first two above are recommended. This will return undefined if the string is empty, whereas the other alternatives will all return the null string.
Another idea is
string.split("")[charpos]
Finally, there is
string.slice(charpos,1)
Since you want a single character at a time I'd recommend charAt.

Elaborating on #elclanrs answer:
var nric = 'S1234567'
var numVal = 0; for(var i = 1, bound = nric.length; i < bound; i++){
numVal += parseInt(nric[i]);
}
if(nric[0] === 'S' && numVal === 28){
alert('ok');
}else{
alert('wrong');
}
should more or less do the trick.
I trust, You can do the multiplying yourself :-)

Related

Extending a Variable's Length With Random Numbers Doesn't Work

I am making an AI that tries to solve a user-inputted "numberle" in JavaScript. I don't want the user to do extra work just to see an AI do it's thing, so on the input field, if the user inputs a number that has less than 5 digits, the JavaScript should add random numbers at the end of the variable, until it has a total of five digits.
I used all the loops I had experience with, under an if statement, so if the length of the input was less than 5 (like 3), the loop will add 5 - the number of digits of the input (2) digits that are random, using the Math.random attribute.
Here is the code I currently have:
if (input.length < 5)
do {
input = (input * 10) + Math.floor(Math.random() * 9) + 1;
} while (input.length < 5);
}
console.log(input)
I have also used the for and while loops with basically the same condition (obviously modified for the if loop; made a variable for input.length so that it has the same value).
Here is what I get in the console:
5 // Inputted number (1 digit)
52 // Inputted digit + random number
As you can see, the loop only runs once, although it should've ran 3 more times. I am using strict mode also. My code editor is github.dev, and I am using the CodeSwing console.
If input is a number, it will not have "length", since it is not a string.
You can achieve the desired result like this:
let input = 5;
let digits = 2;
while (input < 10**(digits-1)) input = ~~((input+Math.random())*10);
console.log(input);
Note that ~~ is a compact way of doing Math.floor()
Alternatively, without a while loop:
let input = 5, digits = 2, M = Math; L = x=>~~(M.log(x)/M.log(10))+1;
input = ~~((input+M.random())*10**(digits - L(input)));
console.log(input);

How to remove the numbers that already occur with their digits reversed

I need a function that will take an array of numbers, and which will return an array that only retains the numbers that are unique in their digit sequence, i.e. that only occur once even if you would reverse their digits.
This is my code so far:
var a=[5,8,3,8,3,7,5,12,21];
console.log(a);
let output=[...new Set([...a])] // it removes the repeated data...
console.log(output);
This works for the numbers 3, 8 and 5, whose duplicates are removed, but the value 21 should also be removed, because there is already 12, which is 21 with the digits in reversed order.
How can I achieve that?
The expected output for the above example is:
[5,8,3,7,12]
My code returns:
[5,8,3,7,12,21]
You need (of course) to include the logic of reversing digits in a number.
I will assume that when the rightmost digit of a number is 0, that the reversal of that number is not defined. So the reversal of 19 is 91, but the reversal of 190 is not 91, but undefined (or NaN).
First define a function for that reversal of digits, and then use the idea of building a set:
function reverseDigits(num) {
// A Number should not have 0 as first digit
// unless it is 0
if (num && num % 10 == 0) return NaN;
return +[...String(num)].reverse().join("");
}
function specialUnique(a) {
const set = new Set;
for (const value of a) {
if (!set.has(value) && !set.has(reverseDigits(value))) {
set.add(value);
}
}
return [...set];
}
// Example input
const a = [5,8,3,8,3,7,5,12,21];
const output = specialUnique(a);
console.log(output);
You can use the filter.
let valueToRemove = 21;
output = output.filter((item) => item !== valueToRemove);

Having a tough time understanding longestPalindrome algorithm

I found this solution to make sense to an algorithm question about finding the longest palindrome in a substring. However, I am struggling to understand what the expand function is actually doing. I thought it would run from the center, but console logging is showing that it is run for the whole string. I am having difficulty understanding why it's entering the while loop for any character that's not the same as s[begin] === s[end] that's what I thought this line was preventing. I am not sure why expand is called twice either. Also, why do we add begin + 1 rather than just begin when returning the substring. The code is below. Any clarification of how the expand works would be appreciated.
var longestPalindrome = function (s) {
//either when empty string or is a single character
if (!s || s.length <= 1) return s
let longest = s.substring(0, 1)
for (let i = 0; i < s.length; i++) {
let temp = expand(s, i, i, 'first')
// console.log(temp, 'i am the first')
if (temp.length > longest.length) {
longest = temp
}
temp = expand(s, i, i + 1, 'second')
// console.log(temp, 'i am the second')
if (temp.length > longest.length) {
longest = temp
}
}
return longest
}
const expand = (s, begin, end, counter) => {
while (begin >= 0 && end <= s.length - 1 && s[begin] === s[end]) {
console.log(s, 'i am string')
console.log(begin, 'i am begin')
console.log(end, 'i am begin')
console.log(s[begin], s[end])
console.log(counter)
begin--
end++
}
return s.substring(begin + 1, end)
}
console.log(longestPalindrome('cbbd'))
console.log(longestPalindrome('babad'))
console.log(longestPalindrome('ac'))
console.log(longestPalindrome('abb'))
Well, let's say we want to find the palindrome of s when s = 'abba'.
note: Think of expansion as a palindrome finder that takes in the center index. Keep in mind that I'll explain how does expansion work afterwards
We'll shift the center of the expansion from 0 to 3(the final index). First, it checks the the expansion from begin = 0 and end = 0.
s = 'abba'
If begin = 0 and end = 0, expansion returns 'a'.
v___
abba //only the palindrome from 0 is 'a'
If begin = 0 and end = 1, expansion returns ' '.
_v___
a bba //there are no palindrome from between 0 and 1
If begin = 1 and end = 1, expansion returns 'b'.
_v__
abba //only the palindrome from 1 is 'b'
If begin = 1 and end = 2, expansion returns 'abba'.
__v__
ab ba //the palindrome from between b and b is 'abba'
If begin = 2 and end = 2, expansion returns 'b'.
If begin = 2 and end = 3, expansion returns ' '.
If begin = 3 and end = 3, expansion returns 'a'.
At this point, we've tested all the possible palindrome of s. Finally, the code returns the longest palindrome so far, which will be 'abba' in this case.
Notice why we need to perform expansion twice. At i = 1, we can look for a palindrome from the center.
_v__
abba
But also from the place between b and b
__v__
ab ba
Former returns 'b' while latter returns 'abba'. This is why you need to perform 2 expansions for each i.
Now, what exactly happens inside the expand function?
Let's use the example. s = 'aacdeedcba', and begin = 4 and end = 5.
First, the while loop checks if s[begin] == s[end].
____vv____
aacdeedcba
Obviously 'e' === 'e' is true, so we'll shift begin to left side, and end to right side .
Again we'll check if s[begin] === s[end].
___v__v____
aacdeedcba
Again, 'd' === 'd' is true, so we'll shift begin to left side, and end to right side .
we'll check again.
__v____v__
aacdeedcba
Again, 'c' === 'c' is true, so we'll shift begin to left side, and end to right side .
we'll check again.
_v______v_
aacdeedcba
This time, 'a' === 'b' is not true. So the while loop is stopped. And the expansion function returns 'cdeedc'.
However, I am struggling to understand what the expand function is actually doing. I thought it would run from the center, but console logging is showing that it is run for the whole string
Palindromes can be of two types
1. Even length palindromes e.g. - "abba"
2. Odd length palindromes e.g. - "aba"
Now, each index of the given string can be center of either of these types of palindromes.
So, every index of the string is tested for this possibility.
longestPalindrome function takes the string and for each index of the string it tests that index as center of an odd length palindrome and an even length palindrome.
expand function takes the two center indices and begins expanding them outwards. For an odd length palindrome, the center character should be compared with itself. So, expand is called with both begin and end as same index.
I am having difficulty understanding why it's entering the while loop for any character that's not the same as s[begin] === s[end] that's what I thought this line was preventing.
The longestPalindrome will send the two indices such that this condition s[begin] === s[end] is not true but the while loop will check and not expand them further. You can prevent this functionality from the longestPalindrome function if you want to.
I am not sure why expand is called twice either.
It is because of the two types of palindromes on the basis of their length. You need to test for both these types.
Also, why do we add begin + 1 rather than just begin when returning the substring.
It is because begin is one off when if comes out of the while loop. You can do a simulation on paper to understand better.

Make choice from array semi-randomly based on string

I have this problem. I'd like to make random a choice from array [1,2,3,4] based on arbitrary 6 letter string in such way that this choice is always same if string is same.
So if i have string 'dogdog' function would return always '3' for example, but '4' for 'bigcat' etc.
I think the solution might be first hashing the string. How could one convert hash string into choice from array?
You can calculate a hash from a string and take the array item at [hash % array.length]. An example with the DJB hashfunc (see http://www.cse.yorku.ca/~oz/hash.html for more):
function djbHash(s) {
let hash = 5381;
for (let c of s) {
hash = hash * 33 + c.charCodeAt(0);
}
return hash;
}
function mapToValues(s, values) {
return values[djbHash(s) % values.length];
}
console.log(mapToValues('dogdog', [1, 2, 3, 4]));
console.log(mapToValues('bigcat', [1, 2, 3, 4]));
A really simple hash function:
Change each letter of your word by a number (a is 1, b is 2, etc.). Let's call w the whole word changed in a number.
Calculate i = w mod 4. i will be a number between 0 and 3. Add 1 to it.
Congrats, you can now associate any word to a "random" number between 1 and 4. You can of course replace 4 by any other number to associate each world to a random number in any range.

How to increment a numeric string by +1 with Javascript/jQuery

I have the following variable:
pageID = 7
I'd like to increment this number on a link:
$('#arrowRight').attr('href', 'page.html?='+pageID);
So this outputs 7, I'd like to append the link to say 8. But if I add +1:
$('#arrowRight').attr('href', 'page.html?='+pageID+1);
I get the following output: 1.html?=71 instead of 8.
How can I increment this number to be pageID+1?
Try this:
parseInt(pageID, 10) + 1
Accordint to your code:
$('#arrowRight').attr('href', 'page.html?='+ (parseInt(pageID, 10) + 1));
+ happens to be valid operator for both strings and numbers that gives different results when both arguments are numeric and when at least one is not. One of possible workarounds is to use operator that only have numeric context but gives same mathematical result, like -. some_var - -1 will always be same as adding 1 to some_var's numeric value, no matter if it is string or not.
$('#arrowRight').attr('href', 'page.html?='+ (pageID - -1));
All these solutions assume that your number you want to add 1 to is within the machine precision for an integer. So if you have a large enough number within that string when you add 1 to it won't change the number.
For Example:
parseInt('800000000000000000', 10) + 1 = 800000000000000000
So I wrote a quick solution to the problem
function addOne(s) {
let newNumber = '';
let continueAdding = true;
for (let i = s.length - 1; i>= 0; i--) {
if (continueAdding) {
let num = parseInt(s[i], 10) + 1;
if (num < 10) {
newNumber += num;
continueAdding = false;
} else {
newNumber += '0';
}
} else {
newNumber +=s[i];
}
}
return newNumber.split("").reverse().join("");
}
Now, using the same example above
addOne('800000000000000000') + 1 = '800000000000000001'
Note that it must stay as a string or you will lose that 1 at the end.
It needs to be a integer, not a string. Try this:
pageID = parseInt(pageID)+1;
Then you can do
$('#arrowRight').attr('href', 'page.html?='+pageID);
Simply, $('#arrowRight').attr('href', 'page.html?='+(pageID+1));
The parentheses makes the calculation done first before string concatenation.
let pageId = '7'
pageId++
console.log(pageId)
Nowadays, you just need to pageID++.
Just change your order of operations by wrapping your addition in parentheses; if pageID is already a number, parseInt() isn't necessary:
$('#arrowRight').attr('href', 'page.html?='+(pageID+1));
Demo
As long as your pageID is numeric, this should be sufficient:
$('#arrowRight').attr('href', 'page.html?='+(pageID+1));
The problem you were seeing is that JavaScript normally executes in left-to-right order, so the string on the left causes the + to be seen as a concatenator, so it adds the 7 to the string, and then adds 1 to the string including 7.

Categories

Resources