jaal kamza
jaal kamza

Reputation: 363

Regex to match user input and convert into Javascript object

I'm currently trying to parse some user input into some regex groups so I can put the following inputs into the outputs.

The current regex I have is

^[0-9]+[d,D,h,H,m,M]$

This successfully matches a single date, for example 1d or 2h. However, I need it to dynamically work for every single one, even if some are not provided by the user.

input: "5d"
output: {days: 5, hours: 0, minutes: 0}

input: "1d 2h"
output: {days: 1, hours: 2, minutes: 0}

input: "1d 5h 2m"
output: {days: 1, hours: 5, minutes: 2}

input: "2m"
output: {days: 0, hours: 0, minutes: 2}

The output doesn't necessarily have to be in a js object, simply using regex groups would also be beneficial and something I could work with.

Any help would be very appreciated as I'm not sure what else to do.

Upvotes: 2

Views: 174

Answers (4)

Nick
Nick

Reputation: 147156

You could expand your regex to include three named capture groups for the days, hours and minutes, then use the group values to populate an output object:

const parseInterval = s => { 
  let res = regex.exec(s) || {}
  return { 
    days : +res.groups.days || 0,
    hours : +res.groups.hours || 0,
    minutes : +res.groups.minutes || 0
  }
}

const input = [ "5d", "1D 2h", "1d 5H 2m", "2M"]
const regex = /(?:(?<days>\d+)d)?\s*(?:(?<hours>\d+)h)?\s*(?:(?<minutes>\d+)m)?/i

const result = input.map(parseInterval)

console.log(result)

Upvotes: 3

vanowm
vanowm

Reputation: 10201

You can use RegExp.exec() to get all global matches with a single regex:

function parseDate(input)
{
  const reg = /([0-9]+)([dhm])(?=[0-9\s]|$)/gi,
        result = {days: 0, hours: 0, minutes: 0},
        map = {d: "days", h: "hours", m: "minutes"};

  let match;
  while((match = reg.exec(input.value)))
    result[map[match[2]]] += +match[1]; //this will sum multiple matched values ie "1d 2d 3d" will become 6 days remove "+" from "+=" if this behaviour is not desired

  console.clear();
  console.log(result);
}

parseDate(dateInput);
<input id="dateInput" oninput="parseDate(this)" value="3d 2h 1m">

Upvotes: 3

Peter Thoeny
Peter Thoeny

Reputation: 7616

Here is a way if you can live with 3 regex to fill the object:

let input = [
  '5d',       // {days: 5, hours: 0, minutes: 0}
  '1d 2h',    // {days: 1, hours: 2, minutes: 0}
  '1d 5h 2m', // {days: 1, hours: 5, minutes: 2}
  '2m'        // {days: 0, hours: 0, minutes: 2}
].forEach(str => {
  let d = str.match(/\b([0-9]+)d\b/);
  let h = str.match(/\b([0-9]+)h\b/);
  let m = str.match(/\b([0-9]+)m\b/);
  let obj = {
    days:    d ? Number(d[1]) : 0,
    hours:   h ? Number(h[1]) : 0,
    minutes: m ? Number(m[1]) : 0,
  }
  console.log(str + ' => ' + JSON.stringify(obj));
});

Result:

5d => {"days":5,"hours":0,"minutes":0}
1d 2h => {"days":1,"hours":2,"minutes":0}
1d 5h 2m => {"days":1,"hours":5,"minutes":2}
2m => {"days":0,"hours":0,"minutes":2}

Upvotes: 2

Mina Makar
Mina Makar

Reputation: 81

you can use a function like this

const myfun = (s) => {
    const days = s.match(/[0-9]+[d,D]/) ? s.match(/[0-9]+[d,D]/)[0] : "0d" 
    const hours = s.match(/[0-9]+[h,H]/) ? s.match(/[0-9]+[h,H]/)[0] : "0d" 
    const minutes = s.match(/[0-9]+[m,M]/) ? s.match(/[0-9]+[m,M]/)[0] : "0d" 

return  {
        days: days.slice(0, -1),
        hours: hours.slice(0, -1),
        minutes:minutes.slice(0, -1)
    }
}

console.log(myfun("5d")) // {days: 5, hours: 0, minutes: 0}
console.log(myfun("1d 2h")) // { days: '1', hours: '2', minutes: '0' }
console.log(myfun("1d 5h 2m")) // { days: '1', hours: '5', minutes: '2' }
console.log(myfun("2m")) // { days: '0', hours: '0', minutes: '2' }
console.log(myfun("randomString")) // { days: '0', hours: '0', minutes: '0' }

Upvotes: 1

Related Questions