Mask the last two digits of a date in JavaScript using regex - javascript

I’m trying to demonstrate how a date would look like if it was displayed with some characters masked. Specifically, something like this:
10 August 2018 => 10 August 20**
10 August 2018 => 10 August **** (and this too if possible)
I’ve spent some time looking for working examples on here but haven’t found one for this specific example. In my own experiments I only ever end up with one asterisk (10 August 19*) instead of one per character.
It all needs to happen within a textToMask.replace(regex, '*').
I know you’d never use this in production; it’s for a visual demo.

You can use padEnd method
function maskIt(str, pad = 1) {
const slicedStr = str.slice(0,pad*-1);
const masked = slicedStr.padEnd(str.length, '*');
console.log(masked);
}
maskIt("10 August 2018",2);
maskIt("10 August 2018",4);

Here's a dirt simple mask() function, that works with any string, and doesn't involve regex:
function mask(str, amt = 1) {
if (amt > str.length) {
return '*'.repeat(str.length);
} else {
return str.substr(0, str.length-amt) + '*'.repeat(amt);
}
}
console.log(mask('10 August 2018', 2));
console.log(mask('10 August 2018', 4));
console.log(mask('test', 5));

Here is a very simple function that uses a regular expression to find a given number of digits at the end of a given date and substitutes them with an equal number of asterisks.
Example:
const mask_date = (date, n) => date.replace(new RegExp(`[\\d]{${n}}$`), "*".repeat(n));
console.log(mask_date("10 August 2018", 2));
console.log(mask_date("10 August 2018", 4));

Please note that I would really like to refactor this somehow, I just don't have the time to do it right now. Check back at some point tomorrow I may have made an edit to this to make the code flow a bit better.
I am using the second version of the String.prototype.replace function that allows you to pass a function instead of a string as the second parameter. Check the link to learn more.
This is a very rough function -- I unfortunately did not have a lot of time to write this out.
// str - string to be altered, pattern - regex pattern to look through, replacement - what to replace the found pattern with, match_length - do we match the length of replacement to the length of what it is replacing?
function mask(str, pattern, replacement="*", match_length=true){
return str.replace(pattern, function(whole, group){
//init some values;
let padLength = 0, returned = '';
// if the group is not a number, then we have a regex that has a grouping. I would recommend limiting your regex patterns to ONE group, unless you edit this.
if(typeof group != 'number'){
padLength = group.length;
returned = whole.slice(0, whole.indexOf(group)) + (replacement.repeat(match_length ? padLength : 1));
}else{
padLength = whole.length;
returned = replacement.repeat(match_length ? padLength : 1);
}
return returned;
});
}
let randomBirthdayString = 'April 3 2002';
console.log(mask(randomBirthdayString, /\d{2}(\d{2})$/) );
console.log(mask(randomBirthdayString, /\d{2}(\d{2})$/, 'x') );
console.log(mask(randomBirthdayString, /\d{2}(\d{2})$/, 'x', false) );

You can use the code below.
textToMask.replace(/..$/, '**')

Related

How to extract years from a string that contains a date range [Typescript/Angular]

I'm a beginner in Typescript. I have a date range which I'm receiving as a string.
var range="7-01-2018 VS 5-01-2019";
It is hard coded right now just to explain you. But it will be in this string form only later also. I've to extract 2018 and store it in some variable, say startYear and also I've to extract 2019 and store it in endYear variable. So that later I can compare them and apply validations.
I tried using:
substring(start,end)
My code worked but the problem is that the string will change its length when a double digit date is selected. For eg:
7-01-2018 VS 25-01-2019 or
17-01-2018 VS 5-01-2019 or
27-01-2018 VS 25-01-2019
In these cases start and end will have different meanings. What should I do now. Please help me.
My method is:
myValidator() {
range="7-01-2018 VS 5-01-2019";
startYear=range.substring(5,8);
endYear=range.substring(18,21);
if(endYear<startYear) {
console.log("Invalid range");
}
}
Now I'm planning to use split(). And split the string into different parts and then write some logic with that. But the problem with split is that there's a VS in between. However for separator parameter i can give - symbol. Please correct me if I'm wrong.
you are right split will be good
myValidator() {
range="7-01-2018 VS 5-01-2019";
startYear=parseInt(range.split("VS")[0].split("-")[2])
endYear=parseInt(range.split("VS")[1].split("-")[2])
if(endYear<startYear) {
console.log("Invalid range");
}
}
All in one line
const [,startYear,endYear]=range.match(/.*-(\d{4}) VS .*-(\d{4})$/);
Using String.prototype.match
const range = '7-01-2018 VS 25-01-2019'
const [...range.matchAll(/\d{0,2}-\d{0,2}-(\d{0,4})/g)].map((date)=> date[1])
Using split, Date and reduce:
console.log("7-01-2018 VS 25-01-2019: ", checkRange("7-01-2018 VS 25-01-2019"));
console.log("7-01-2019 VS 25-01-2018: ", checkRange("7-01-2019 VS 25-01-2018"));
function checkRange(inputRange) {
const range = inputRange.split(" VS ");
const getYear = dateStr =>
new Date(dateStr.split("-").reverse().join("-")).getFullYear();
const years = range.reduce( (acc, val) => [...acc, getYear(val)], []);
return years[0] < years[1];
}
.as-console-wrapper { top: 0; max-height: 100% !important; }
Try this one, edited for array of integers as Output
myValidator() {
range = "7-01-2018 VS 5-01-2019";
regEx = /\d{4}/g;
return (range.match(regEx).map(x => parseInt(x,10));
}
Output :
[ 2018, 2019 ]

How can I convert a time into the correct format? [duplicate]

I am receiving a string in this format 'HH:mm:ss'. I would like to remove the leading zeros but always keeping the the last four character eg m:ss even if m would be a zero. I am formatting audio duration.
Examples:
00:03:15 => 3:15
10:10:10 => 10:10:10
00:00:00 => 0:00
04:00:00 => 4:00:00
00:42:32 => 42:32
00:00:18 => 0:18
00:00:08 => 0:08
You can use this replacement:
var result = yourstr.replace(/^(?:00:)?0?/, '');
demo
or better:
var result = yourstr.replace(/^0(?:0:0?)?/, '');
demo
To deal with Matt example (see comments), you can change the pattern to:
^[0:]+(?=\d[\d:]{3})
If you use 1 h instead of two you will not get the leading 0.
h:mm:ss
Another option is to use moment.js libary.
This supports formats such as
var now = moment('1-1-1981 2:44:22').format('h:mm:ss');
alert(now);
http://jsfiddle.net/8yqxh5mo/
You could do something like this:
var tc =['00:03:15', '10:10:10','00:00:00','04:00:00','00:42:32','00:00:18','00:00:08'];
tc.forEach(function(t) {
var y = t.split(":");
y[0] = y[0].replace(/^[0]+/g, '');
if(y[0] === '') {
y[1] = y[1].replace(/^0/g, '');
}
var r = y.filter(function(p) {return p!=='';}).join(':');
console.log(r);
});
Divide the time in 3 parts. Remove the leading zeroes from first part, if the the first part is empty remove the leading zeroes from the second part otherwise keep it. Then join all of them discarding the empty strings.
I had a problem with ZUL time when simply format with one small 'h' moment(date).format('h:mm A') cuts first digit from time:
and my const arrivalTime = "2022-07-21T12:10:51Z"
const result = moment(arrivalTime).format(('h:mm A')) // 2:10 PM
Solution for that was converting that to ISO format and then format:
const arrivalTimeIsoFormat = arrivalTime.toISOString()
const result = moment(arrivalTimeIsoFormat, "YYYY-MM-DDTHH:mm:ss.SSS").format(('h:mm A')) // 12:10 PM

What's the best way to mask a credit card in JavaScript?

In Node, I need to turn a credit card into something like this before rendering the view layer: ************1234.
Without loops and ugliness is there a utility or one liner for this? The credit card can potentially look one of these ways:
1234567898765432
1234-5678-9876-5432
1234 5678 9876 5432
Here's one way with Ramda and some RegEx:
var ensureOnlyNumbers = R.replace(/[^0-9]+/g, '');
var maskAllButLastFour = R.replace(/[0-9](?=([0-9]{4}))/g, '*');
var hashedCardNumber = R.compose(maskAllButLastFour, ensureOnlyNumbers);
hashedCardNumber('1234567898765432'); // ************5432
Demo : http://jsfiddle.net/7odv6kfk/
No need for a regex:
var cc='1234-5678-9012-3456';
var masked = '************'+cc.substr(-4); // ************3456
Will work for any format provided the last four digits are contiguous.
This is for everyone who said they didn't need another way to mask a credit card. This solution will append the last 4 chars of the card number with asterisk.
var cardNumber = '4761640026883566';
console.log(maskCard(cardNumber));
function maskCard(num) {
return `${'*'.repeat(num.length - 4)}${cardNumber.substr(num.length - 4)}`;
}
jsfiddle example
I use this function that is useful for me, because mask the credit card number and format it in blocks of four characters like this **** **** **** 1234, here the solution:
const maskCreditCard = (card) => {
return card
.replace(/.(?=.{5})/g, "*")
.match(/.{1,4}/g)
.join(" ");
};
Here's plain JavaScript using Regex with lookahead
var cardNumbers = [
"1234567898765432",
"1234-5678-9876-5432",
"1234 5678 9876 5432"
];
console.log(cardNumbers.map(maskCardNumber));
//> ["************5432", "************5432", "************5432"]
function maskCardNumber(cardNumber) {
return cardNumber.replace(/^[\d-\s]+(?=\d{4})/, "************");
};
Unlike AllienWebguy's implementation:
doesn't require an external library
does everything in one replace() call
replaces whatever number of digits with the constant number of asterisks (it should be a bit faster, but it may not be what you want)
supports only described formats (will not work, for example, with "1B2C3D4E5F6G7H89876-5432" or "1234+5678+9876=54-32")
Remove non digits, generate an asterisk string of that length - 4, append the last 4:
var masked = Array(cc.replace(/[^\d]/g, "").length - 3).join("*") + cc.substr(cc.length - 4);
Or to include space/hyphens in the mask:
var masked = Array(cc.length - 3).join("*") + cc.substr(cc.length - 4);

check input value for specific format using Javascript

I have an input field that allows a user to enter a date.
I need this date to be in the following format: 10Jan13 (capitalization is not important)
There is a popup calender that if used will format the date correctly for the user.
I'd like to check the value of the input onblur using Javascript to be sure that the user did not either paste or type the date improperly.
I am currently checking number-only fields like this:
var numbers = /^[0-9]+$/;
if (!BIDInput.value.match(numbers))
{
checkedInput.value = "";
alert('Not a number');
}
and I'm checking letters-only fields like this:
var letters = /^[a-z]+$/
if (!nameInput.value.match(letters))
{
nameInput.value = "";
alert('Not a letter');
}
I would like to check the date format in a similar a fashion if possible. But anything that accomplishes the task will do. Can anyone point me in the right direction on how to get this done?
I know that client side validation does not replace server side validation. This is for user experience purposes only.
You're pretty much there with what you have. Basically your format is one or two digits, then one of 12 possible strings, followed by two digits. So for instance:
var shortDateRex = /^\d{1,2}(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\d{2}$/;
Breakdown:
^ Start of string.
\d{1,2} One or two digits.
(:?...) A non-capturing group. Or you could use a capture group if you like.
Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec An alternation, allowing any of those twelve choices. Naturally you can add more if you like. If you have two choices that start the same way (Jan and January, for instance), put the longer one earlier in the alternation.
\d{2} Two digits.
Side note: I'd have to recommend against two-digit dates on principle, and particularly given where in the century we currently are!
Responding to Amberlamps' comment that this doesn't validate the date: Once you've validated the format, it's trivial to then check the date itself if you like (to rule out 30Feb13, for instance):
var validateDateString = (function() {
var monthNames = "Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec".toLowerCase().split("|");
var dateValidateRex = /^(\d{1,2})(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)(\d{2})$/i;
var arbitraryCenturyCutoff = 30;
function validateDateString(str) {
var match;
var day, month, year;
var dt;
match = dateValidateRex.exec(str);
if (!match) {
return false;
}
day = parseInt(match[1]);
month = monthNames.indexOf(match[2].toLowerCase()); // You may need a shim on very old browsers for Array#indexOf
year = parseInt(match[3], 10);
year += year > arbitraryCenturyCutoff ? 1900 : 2000;
dt = new Date(year, month, day);
if (dt.getDate() !== day ||
dt.getMonth() !== month ||
dt.getFullYear() !== year) {
// The input was invalid; we know because the date object
// had to adjust something
return false;
}
return true;
}
return validateDateString;
})();
...or something along those lines.
Live Example | Source
Or if (like me) you hate to see a list like that list of month names repeated you can use the RegExp constructor with a string instead, but you have to remember to duplicate your backslashes:
var monthNamesString = "Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec";
var monthNames = monthNamesString.toLowerCase().split("|");
var dateValidateRex = new RegExp("^(\\d{1,2})(" + monthNamesString + ")(\\d{2})$", "i");
Live Example | Source
You would use the following regular expression to check for a string starting with 2 numbers, followed by 3 characters followed by 2 numbers
[0-9]{2}[a-zA-Z]{3}[0-9]{2}

Is there "0b" or something similar to represent a binary number in Javascript

I know that 0x is a prefix for hexadecimal numbers in Javascript. For example, 0xFF stands for the number 255.
Is there something similar for binary numbers ? I would expect 0b1111 to represent the number 15, but this doesn't work for me.
Update:
Newer versions of JavaScript -- specifically ECMAScript 6 -- have added support for binary (prefix 0b), octal (prefix 0o) and hexadecimal (prefix: 0x) numeric literals:
var bin = 0b1111; // bin will be set to 15
var oct = 0o17; // oct will be set to 15
var oxx = 017; // oxx will be set to 15
var hex = 0xF; // hex will be set to 15
// note: bB oO xX are all valid
This feature is already available in Firefox and Chrome. It's not currently supported in IE, but apparently will be when Spartan arrives.
(Thanks to Semicolon's comment and urish's answer for pointing this out.)
Original Answer:
No, there isn't an equivalent for binary numbers. JavaScript only supports numeric literals in decimal (no prefix), hexadecimal (prefix 0x) and octal (prefix 0) formats.
One possible alternative is to pass a binary string to the parseInt method along with the radix:
var foo = parseInt('1111', 2); // foo will be set to 15
In ECMASCript 6 this will be supported as a part of the language, i.e. 0b1111 === 15 is true. You can also use an uppercase B (e.g. 0B1111).
Look for NumericLiterals in the ES6 Spec.
I know that people says that extending the prototypes is not a good idea, but been your script...
I do it this way:
Object.defineProperty(
Number.prototype, 'b', {
set:function(){
return false;
},
get:function(){
return parseInt(this, 2);
}
}
);
100..b // returns 4
11111111..b // returns 511
10..b+1 // returns 3
// and so on
If your primary concern is display rather than coding, there's a built-in conversion system you can use:
var num = 255;
document.writeln(num.toString(16)); // Outputs: "ff"
document.writeln(num.toString(8)); // Outputs: "377"
document.writeln(num.toString(2)); // Outputs: "11111111"
Ref: MDN on Number.prototype.toString
As far as I know it is not possible to use a binary denoter in Javascript. I have three solutions for you, all of which have their issues. I think alternative 3 is the most "good looking" for readability, and it is possibly much faster than the rest - except for it's initial run time cost. The problem is it only supports values up to 255.
Alternative 1: "00001111".b()
String.prototype.b = function() { return parseInt(this,2); }
Alternative 2: b("00001111")
function b(i) { if(typeof i=='string') return parseInt(i,2); throw "Expects string"; }
Alternative 3: b00001111
This version allows you to type either 8 digit binary b00000000, 4 digit b0000 and variable digits b0. That is b01 is illegal, you have to use b0001 or b1.
String.prototype.lpad = function(padString, length) {
var str = this;
while (str.length < length)
str = padString + str;
return str;
}
for(var i = 0; i < 256; i++)
window['b' + i.toString(2)] = window['b' + i.toString(2).lpad('0', 8)] = window['b' + i.toString(2).lpad('0', 4)] = i;
May be this will usefull:
var bin = 1111;
var dec = parseInt(bin, 2);
// 15
No, but you can use parseInt and optionally omit the quotes.
parseInt(110, 2); // this is 6
parseInt("110", 2); // this is also 6
The only disadvantage of omitting the quotes is that, for very large numbers, you will overflow faster:
parseInt(10000000000000000000000, 2); // this gives 1
parseInt("10000000000000000000000", 2); // this gives 4194304
I know this does not actually answer the asked Q (which was already answered several times) as is, however I suggest that you (or others interested in this subject) consider the fact that the most readable & backwards/future/cross browser-compatible way would be to just use the hex representation.
From the phrasing of the Q it would seem that you are only talking about using binary literals in your code and not processing of binary representations of numeric values (for which parstInt is the way to go).
I doubt that there are many programmers that need to handle binary numbers that are not familiar with the mapping of 0-F to 0000-1111.
so basically make groups of four and use hex notation.
so instead of writing 101000000010 you would use 0xA02 which has exactly the same meaning and is far more readable and less less likely to have errors.
Just consider readability, Try comparing which of those is bigger:
10001000000010010 or 1001000000010010
and what if I write them like this:
0x11012 or 0x9012
Convert binary strings to numbers and visa-versa.
var b = function(n) {
if(typeof n === 'string')
return parseInt(n, 2);
else if (typeof n === 'number')
return n.toString(2);
throw "unknown input";
};
Using Number() function works...
// using Number()
var bin = Number('0b1111'); // bin will be set to 15
var oct = Number('0o17'); // oct will be set to 15
var oxx = Number('0xF'); // hex will be set to 15
// making function convTo
const convTo = (prefix,n) => {
return Number(`${prefix}${n}`) //Here put prefix 0b, 0x and num
}
console.log(bin)
console.log(oct)
console.log(oxx)
// Using convTo function
console.log(convTo('0b',1111))

Categories

Resources