Lets say I had a variable called test and test = 123456789;. Then I have another variable called anotherTest and anotherTest = 1234;. How would I make a program that can test whether a variable has the digit 5 or not? Then, how could it sort the variables into two groups of which one group of variables has the digit "5" within it and the other without? Is there a easy way to do this?
How would I make a program that can test whether a variable has the digit 5 or not?
You can readily do that with strings and indexOf:
if (String(test).indexOf("5") !== -1) {
// It has a 5 in it
}
Then, how could it sort the variables into two groups of which one group of variables has the digit "5" within it and the other without?
You can't sort the variables into groups, but you can certainly sort values into groups. For example, this loops through an array and adds values to either the with5 or without5 array depending on whether the value contains the digit 5:
var a = [
1234,
12345,
123123,
555555
];
var with5 = [];
var without5 = [];
a.forEach(function(value) {
if (String(value).indexOf("5") === -1) {
without5.push(value);
} else {
with5.push(value);
}
});
snippet.log("with5: " + with5.join(", "));
snippet.log("without5: " + without5.join(", "));
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
The above assumes base 10 (decimal) strings, but you can easily do the same with hexadecimal or octal or any other base you like by using Number#toString(base). E.g.:
var s = num.toString(16);
...will assign s the value of num as a hexadecimal (base 16) string.
Loop through each character of variable test, then compare using indexOf() to see if it exists in anotherTest. If so add to one array, otherwise add to array 2.
To see if a number contains the digit "5", you can just convert the numbers to strings and then just use .indexOf("5") on each string.
var test = 123456789;
var anotherTest = 1234;
// reports whether the passed in number or string contains the
// character "5"
function containsDigit5(val) {
// convert number to string
// if already string, then it is left as is
val = "" + val;
return val.indexOf("5") >= 0;
}
containsDigit5(test); // true
containsDigit5(anotherTest); // false
The grouping part of your question is not entirely clear, but you can just call this function on each variable and add the numbers to one of two arrays.
var testNumbers = [123456789, 1234];
var has5 = [];
var doesNotHave5 = [];
// reports whether the passed in number or string contains the
// character "5"
function containsDigit5(val) {
// convert number to string
// if already string, then it is left as is
val = "" + val;
return val.indexOf("5") >= 0;
}
testNumbers.forEach(function(item) {
if (containsDigit5(item)) {
has5.push(testNumbers[i]);
} else {
doesNotHave5.push(testNumbers[i]);
}
});
You can do this with RegExp, or .indexOf. Either works:
RegEx
Everyone hates RegExp for some reason, but I like it. You can use:
var test = 123456789,
anotherTest = 1234;
/5/.test(test);
/5/.test(anotherTest);
var test = 123456789,
anotherTest = 1234;
document.write( 'test (123456789): ' + /5/.test(test) + '<br/>' );
document.write( 'anotherTest (1234): ' + /5/.test(anotherTest) );
indexOf
This can be faster in some situations, but not always, it is also a bit more "complicated", at least in my opinion:
var test = 123456789,
anotherTest = 1234;
(test+'').indexOf(5) > -1;
(anotherTest+'').indexOf(5) > -1;
var test = 123456789,
anotherTest = 1234;
document.write( 'test (123456789): ' + ((test+'').indexOf(5) > -1) + '<br/>' );
document.write( 'anotherTest (1234): ' + ((anotherTest+'').indexOf(5) > -1) + '<br/>' );
Related
My goal is to edit the string (which has an email) to mask the first part, like say the email is johndoe#abc.com then I should output j*****e#abc.com.
var maskPII = function(S) {
var ans = "";
if(S.includes("#")){
S = S.toLowerCase();
var parts = S.split("#");
var first = parts[0];
for(var i=0;i<parts[0].length;i++){
if(i!=0 && i!=parts[0].length - 1)
first[i] = '*';
}
ans = first +"#" +parts[1];
}else{
}
return ans;
};
However in my loop I can't change the characters to asterisks.
After execution I see value of first still same as parts[0] and has no asterisks, can some one explain why? Also, what would I need to do to modify the variable inside loop?
To answer your question... javascript allows you access values of a string using [] indexing.. but that is read only access... you cannot insert/replace values using that operator.
Ref: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String
When using bracket notation for character access,
attempting to delete or assign a value to these properties will not succeed.
The properties involved are neither writable nor configurable.
(See Object.defineProperty() for more information.)
You need to extract the values you want to keep from the existing string and build up a new string as noted in other answers...
Well, this's what you're looking for, and this will be the output j*****e#abc.com.
var ans = "";
var S = "johndoe#abc.com"; //example
S = S.toLowerCase();
var parts = S.split("#");
var first = "";
for(var i = 0; i < parts[0].length; i++){
if(i != 0 && i != parts[0].length - 1){
first += '*';
}else{
first += parts[0][i];
}
}
ans = first +"#"+ parts[1];
console.log(ans);
Here is the code with your approach:
var maskPII = function(S) {
var ans = "";
if(S.includes("#")){
S = S.toLowerCase();
var parts = S.split("#");
var first = parts[0][0];
for(var i=0;i<parts[0].length;i++){
if(i!=0 && i!=parts[0].length - 1)
first += '*';
}
ans = first + parts[0][parts[0].length - 1] +"#" +parts[1];
}else{
}
return ans;
};
But if i were you i would use:
var mail = "johndoe#abc.com";
mail = mail.replace(/(?<=.)(.+?)(?=.#)/gi, '*'.repeat(mail.split('#')[0].length - 2));
console.log(mail);
You can use the bracket notation on a string (like an array) to get the character at a specific index, but you can't use this to change characters. So first[i] = '*' in your code wont do anything.
Strings in JavaScript are immutable. This means that if you want to change a string, a new string instance will be created. This also means that when you change a string in a for-loop, it can impact performance. (Although in this case the difference wont be noticeable.
)
I would use this code:
function maskPII(str) {
const indexOfAt = str.indexOf('#');
if (indexOfAt <= 2) {
return str;
}
return str[0] + '*'.repeat(indexOfAt - 2) + str.substring(indexOfAt - 1);
}
const email = 'johndoe#abc.com';
console.log(email);
console.log(maskPII(email));
It will look for the index of the # sign. If the index is less or equal than 2, (when not found the index will be -1) it will return the original string.
Otherwise it will get the first character, calculate the amount of asterisks needed (index of the # sign -2) and repeat those and then add the rest of the original string.
I want to extract the last part of this string : "https://steamcommunity.com/profiles/76561198364464404".Just the numbers after '/profiles'.But the problem is the URL can change sometimes.
There are two types of url
1.First one is "https://steamcommunity.com/profiles/76561198364464404" with "/profiles" and then the "id"(id is the numbers after '/profiles').
2."https://steamcommunity.com/id/purotexnuk".Second is this type.Where "/profiles" doesn't exist.
I have come up this code :
let inc;
const index = 27;
const string = 'https://steamcommunity.com/id/purotexnuk';
if (string.includes('profiles')) {
inc = 9;
} else {
inc = 3;
}
console.log(string.slice(index + inc, -1));
The above code checks wheather the string "/profiles" is present.If the string contains "/profiles".inc will be 9.So that slice starts from the right side of the string(url) and ends at the first '/' from the right.inc is 9 becuase "profiles/" length is 9.Similar way if the string(url) contains "id".The slice will start from the end and stop at the first '/' from the right.inc will be 3 becuase "id/" length is 3.
The index is always constant because ,"/profiles" or "/id" only occurs after "https://steamcommunity.com" whose length is 27.Is there any better way i can extract only the profile id or profile name?
(profile id - 76561198364464404)
(profile name - purotexnuk )
You can use regex for this, it will also take care if your url ends with / or has query parameters example https://steamcommunity.com/id/purotexnuk?ref=abc
/.*(?:profiles|id)\/([a-z0-9]+)[\/?]?/i
example:
const regex = /.*(?:profiles|id)\/([a-z0-9]+)[\/?]?/i;
const matches = regex.exec('https://steamcommunity.com/id/purotexnuk');
console.log(matches[1]);
You can split the string with delimiter / and return the last value value from the array;
function getNum(str) {
const arr = str.split('/');
if (!isNaN(arr[arr.length - 1])) {
return arr[arr.length - 1];
}
return ' no number ';
}
const st1 = "https://steamcommunity.com/profiles/76561198364464404";
const st2 = "https://steamcommunity.com/profiles/76561198364464404";
const st3 = "https://steamcommunity.com/id/purotexnuk";
console.log(getNum(st1));
console.log(getNum(st2));
console.log(getNum(st3));
Or do it in one line:
const string = 'https://steamcommunity.com/id/purotexnuk';
console.log(string.slice(string.lastIndexOf("/") + 1, string.length));
I have an ASCII character string and I need to convert it to a normal string.
var asciiString = '84114117116104326510811997121115328710511011532'
function strFunc(str) {
var result = []
var strSplit = str.split('');
var validAscii = ['32'];
for(var i=65; i<=90; i++) {
validAscii.push(i.toString());
}
for(var i=97; i<=122; i++) {
validAscii.push(i.toString());
}
strSplit.forEach((item, index) => {
if(validAscii.includes(parseInt(item))) {
result.push(item)
} else if (validAscii.includes(`${parseInt(strSplit[index])}${parseInt(strSplit[index + 1])}`)){
result.push(item)
}
})
return result.fromCharCodeAt(...result)
}
console.log(strFunc(asciiString))
Why does it return an empty string? I need to split the string into either 2 digit or 3 digits and compare it with the array I built.
The string should be split as [84, 114, 117, 116, 104, 32, 65, ...] which translates to TRUTH A....
Please advice.
I'd do this way
const encodedString = '84114117116104326510811997121115328710511011532';
const codes = [];
for (let i = 0; i < encodedString.length;) {
const numDigits = encodedString[i] === '1' ? 3 : 2;
codes.push(encodedString.substr(i, numDigits));
i += numDigits;
}
const str = String.fromCharCode(...codes);
console.log(`"${str}"`);
Some notes:
It assume values in the encoded string go from 32 to 127. There's no error checking
There's no reason to call parseInt as JavaScript will convert numbers strings to numbers so passing the numbers as strings to String.fromCharCode works.
As for why your code doesn't work, a couple of issues include
it's looping over every character, not every code.
It's looping over 8, 4, 1, 1, 4, ... instead of 84, 114, ...
This means neither test will pass since item will never be something found in validAscii which means result will have nothing pushed to it.
There's no function Array.fromCharCodeAt
result is an array and there is no such function as array.fromCharCodeAt. If result had the correct codes in it then you could use String.fromCharCode(...result)
When you're combining two elements of the string, you need to call parseInt() *on the result of the concatenation, not concatenate the results of parseInt(). So it should be:
} else if (validAscii.includes(parseInt(item + strSplit[index+1]))){
And since ASCII values can be 3 digits, you need another else if that looks for item + strSplit[index+1] + strSplit[index+2].
Another problem is that you're pushing item onto the result string. But to get the corresponding character, you need to use String.fromCharCode() to convert the concatenated ASCII code to a character.
strSplit.forEach((item, index) => {
if (validAscii.includes(parseInt(item))) {
result.push(String.fromCharCode(item))
} else if (validAscii.includes(parseInt(item + strSplit[index+1]))) {
result.push(String.fromCharCode(parseInt(item + strSplit[index+1]))
} else if (validAscii.includes(parseInt(item + strSplit[index+1] + strSplit[index+2]))) {
result.push(String.fromCharCode(parseInt(item + strSplit[index+1] + strSplit[index+2]))
}
})
Note that using forEach like this is probably not a good idea. If there are overlapping items in the input that are both in validAscii, you'll add both of them to the result. E.g. if it contains 678 you'll match both 67 and 78, and add the corresponding characters to the result. Instead, you should use an ordinaryfor` loop, and increment the index by the number of characters that you matched.
You want parseInt around the templated string, not the individual items. You were checking if the string is included in an array filled with numbers.
var asciiString = '84114117116104326510811997121115328710511011532'
function strFunc(str) {
var result = []
var strSplit = str.split('');
var validAscii = [32];
for(var i=65; i<=90; i++) {
validAscii.push(i);
}
for(var i=97; i<=122; i++) {
validAscii.push(i);
}
strSplit.forEach((item, index) => {
if(validAscii.includes(parseInt(item))) {
result.push(item)
} else if (validAscii.includes(parseInt(`${(strSplit[index])}${(strSplit[index + 1])}`))){
result.push(item);
}
})
return result.join('');
}
console.log(strFunc(asciiString))
I have the following code that calculates and shows the sum of two values.
var oldprice_formated = parseFloat(oldprice).toFixed(2);
var extraPrice = parseFloat(3).toFixed(2);
if(initials != '') {
var new_price = oldprice_formated + extraPrice;
$('.product-detail .woocommerce-Price-amount.amount').html('<span>€</span>'+new_price);
} else {
$('.product-detail .woocommerce-Price amount.amount').html('<span>€</span>'+oldprice_formated);
}
For example:
oldprice_formated = parseFloat(49.99).toFixed(2);
extraPrice = parseFloat(3.00).toFixed(2)
The expected result: Sum is 52.99
Actual result: Sum is 49.003.00
What am I doing wrong? I assume it's with the number parsing, but not sure what I should change to make it work correctly. Thanks!
.toFixed() returns a string, not a number with only two decimal places.
oldprice_formated = parseFloat(49.99).toFixed(2); // "49.99"
extraPrice = parseFloat(3.00).toFixed(2); // "3.00"
When adding those two variables, instead of a number sum, you're concatenating two strings:
"49.99" + "3.00"; // "49.993.00"
I believe this is what you'll want to do:
var new_price = parseFloat(oldprice_formated) + parseFloat(extraPrice);
Or simply run .toFixed() after you sum those values which were already parsed to floats.
Because toFixed() returns a string, the + operator acts as a string concatenator. If you want it to operate as an addition operator, you must typecast your values as numbers:
let oldprice = 49.99;
let oldprice_formatted = parseFloat(oldprice).toFixed(2);
let extraPrice = parseFloat(3).toFixed(2);
console.log(`string concatenation: ${oldprice_formatted + extraPrice}`)
console.log(`type conversion: ${+oldprice_formatted + +extraPrice}`)
I'm currently stuck on a Codewars challenge that I can't get my head around:
Given a string representation of two integers, return the string representation of those integers, e.g. sumStrings('1','2') // => '3'
I've used the following code so far, but it fails on large number test cases as the number is converted into a scientific notation:
function sumStrings(a,b) {
var res = +a + +b;
return res.toString();
}
Any help would be much appreciated.
Edit:
Fiddle example: https://jsfiddle.net/ag1z4x7d/
function sumStrings(a, b) { // sum for any length
function carry(value, index) { // cash & carry
if (!value) { // no value no fun
return; // leave shop
}
this[index] = (this[index] || 0) + value; // add value
if (this[index] > 9) { // carry necessary?
carry.bind(this)(this[index] / 10 | 0, index + 1); // better know this & go on
this[index] %= 10; // remind me later
}
}
var array1 = a.split('').map(Number).reverse(), // split stuff and reverse
array2 = b.split('').map(Number).reverse(); // here as well
array1.forEach(carry, array2); // loop baby, shop every item
return array2.reverse().join(''); // return right ordered sum
}
document.write(sumStrings('999', '9') + '<br>');
document.write(sumStrings('9', '999') + '<br>');
document.write(sumStrings('1', '9999999999999999999999999999999999999999999999999999') + '<br>');
The problem is that in that specific kata (IIRC), the numbers stored in a and b are too large for a regular 32 bit integer, and floating point arithmetic isn't exact. Therefore, your version does not return the correct value:
sumStrings('100000000000000000000', '1')
// returns '100000000000000000000' instead of '100000000000000000001'
You have to make sure that this does not happen. One way is to do an good old-fashioned carry-based addition and stay in the digit/character based world throughout the whole computation:
function sumStrings(a, b) {
var digits_a = a.split('')
var digits_b = b.split('')
...
}