Reputation: 4438
I have strings like this:
(Feb 28-Mar 1)
(Mar 2-3)
I would like me to return an object as you can see below, someone to give some suggestion how can I do?
function rD(text){
let date = text.replace('(', '').replace(')', '').split(' ');
//const [start, end] = date[2].split("-").map(Number);
return date;
}
console.log(rD("(Feb 28-Mar 1)"))
console.log(rD("(Mar 2-3)"))
Return:
[
{
month: 2,
day: 28
},
{
month: 3,
day: 1
}
]
[
{
month: 3,
day: 2
},
{
month: 3,
day: 3
}
]
Upvotes: 0
Views: 473
Reputation: 27202
Added all the steps inline in below code snippet.
// const str = "(Feb 28-Mar 1)";
const str = "(Mar 2-3)";
// An Object which contains numeric value of months.
const monthMap = {
Jan: 1,
Feb: 2,
Mar: 3
};
/**
* convertStringToObject() method used to convert the input string into an object.
* @param : inputString
*/
function convertStringToObject(inputString) {
// Removing open and closed paranthesis and splitting the inputString with '-'
const split = inputString.replace('(', '').replace(')', '').split('-');
// If splitted array element does not contain month, appending that.
split[1] = (split[1].trim().length === 1) ? split[0].split(' ')[0] + ' ' + split[1] : split[1];
// Looping over the splitted array and then creating the object with keys 'month' and 'day'
return split.map((item) => {
const splittedItem = item.split(' ');
return {
month: monthMap[splittedItem[0]],
day: Number(splittedItem[1])
}
});
}
// Calling the convertStringToObject() method by passing the input string as a param.
console.log(convertStringToObject(str));
Upvotes: 0
Reputation: 6319
Besides the code, the advantage to this approach is that it works if the input is something like Jan 1-3-Mar 7
, while all the other answers don't put this into consideration, thus returning undefined
or an error.
Simple regex and a list of month to numbers should work, and it seems the most straightforward to me. Using String.prototype.match
we can "ignore" all the extra data (i.e. the parentheses and dashes between months), just extract the necessary data:
function rD(str) {
// have a list of the numbers of each month
const monthNum = {
jan: 1,
feb: 2,
mar: 3,
apr: 4,
may: 5,
jun: 6,
jul: 7,
aug: 8,
sep: 9,
oct: 10,
nov: 11,
dec: 12
};
// regex to extract the patterns "Feb 23" or "Aug 15-23"
let spl = str.match(/[a-z]{3} \d{1,2}(\-\d{1,2})?/gi);
// loop through matches
const result = spl.map(s => {
// first 3 letters is the month; get the month number
const month = monthNum[s.substr(0, 3).toLowerCase()],
rest = s.substr(4); // get the rest of the string sans the month and extra space
const e = rest.split("-");
return e.map(q => ({
month,
day: +q
}));
}).flat(); // our array may occasionally be multidimensional if the user provides something like "Nov 7-12". We flatten the array to fix that
return result;
}
console.log("(Feb 28-Mar 1):", rD("(Feb 28-Mar 1)"));
console.log("(Mar 2-3):", rD("(Mar 2-3)"));
console.log("(Nov 7-12-Dec 15):", rD("(Nov 7-12-Dec 15)"));
.as-console-wrapper { min-height: 100% !important; }
Upvotes: 0
Reputation: 17390
I'd remove the parentheses first and then split by /[ -]/
. This way you get an array in one of these two forms
["Feb", "28", "Mar", "1"]
or
["Mar", "2", "3"]
Now if the array has 4 elements the first and third are always the month and second and forth are the day. If the array has 3 elements, the first is a month for both, start and end, the second and third are the days.
For getting the number of the month you can have a simple lookup like
{ Jan:1, Feb:2, ... }
let months = { Jan: 1, Feb: 2, Mar: 3 /* you get the idea*/}
let spans = ["(Jan 28 - Feb 3)", "(Mar 1-3)"]
let parse = (span) => {
let parts = span.replace(/[()]/g, "").split(/[ -]/).filter(x => !!x);
switch (parts.length) {
case 4: return [{month: months[parts[0]], date: +parts[1]}, {month: months[parts[2]], date: +parts[3]}];
case 3: return [{month: months[parts[0]], date: +parts[1]}, {month: months[parts[0]], date: +parts[2]}];
default: return undefined;
}
}
console.log(parse(spans[0]));
console.log(parse(spans[1]))
Upvotes: 2
Reputation: 21
First we are going to create a mapper for the months. like this:
let MonthsMapper = new Map([['Jan', 1], ['Feb', 2], ['Mar', 3] /*...*/])
Then we need a function which cutes the string into chunks by removing the parenthesis and splitting it by its hyphen. The first chunks are the start and end dates. With these two dates we can further get the start month, start day, end month, and end day. (By splitting our chunks by there whitespaces)
There is only one special case I can see from your example and that is the case when the end date does not specify a month, in which case it is implicitly the start month.
let DateObjectParser = (dateString) => {
const [startDate, endDate] = dateString.replace(/[()]/g, '').split('-')
const [startMonth, startDay] = startDate.split(' ')
let [endMonth, endDay] = endDate.split(' ')
// in case a second month is not provided
if (endDay === undefined) {
endDay = endMonth
endMonth = startMonth
}
return [
{
month: MonthsMapper.get(startMonth),
day: parseInt(startDay),
},
{
month: MonthsMapper.get(endMonth),
day: parseInt(endDay),
}
]
}
Upvotes: 1
Reputation: 30685
I'd suggest using a regex pattern to parse each span.
From this we can get the startMonth, startDay, endMonth, endDay. We can then create a getMonthNumber()
function to turn the abbreviated month name (Jan, Feb, etc.) to a number.
function getMonthNumber(month) {
const lookup = { jan: 01, feb: 02, mar: 03, apr: 04, may: 05, jun: 06, jul: 07, aug: 08, sep: 09, oct: 10, nov: 11, dec: 12};
return lookup[(month + '').toLowerCase()]
}
function parseSpan(str) {
const pattern = /\(([a-z]{3})\s+(\d{1,2})\-([a-z]{3})?\s?(\d{1,2})\)/i
const [, startMonth, startDay, endMonth, endDay] = str.match(pattern);
return [
{ month: getMonthNumber(startMonth), day: +startDay },
{ month: getMonthNumber(endMonth || startMonth), day: +endDay }
];
}
let testInputs = [
'(Feb 28-Mar 1)',
'(Mar 2-3)',
'(Sep 28-Oct 31)',
'(Jan 3-17)'
]
testInputs.map(parseSpan).forEach(span => console.log(span))
.as-console-wrapper { max-height: 100% !important; }
Upvotes: 2
Reputation: 601
You can try this
function rangeCalcFunc(range = null) {
if(range && range.length){
const [start, end] = range.substring(1, range.length-1).split("-");
console.log(start);console.log(end);
const [startMon, startDt] = start.split(" ");
const [endMon, endDt] = end.split(" ");
return [
{
month: calcMonthInNumber(startMon.trim()),
date: startDt
},
{
month: calcMonthInNumber(endMon.trim()),
date: endDt
}
]
}
}
function calcMonthInNumber(month) {
switch(month.toLowerCase()){
case 'jan': return '01'
case 'feb': return '02'
//add for other months
default: break;
}
}
console.log(rangeCalcFunc("(Jan 28-Feb 1)"));
Upvotes: 1