How to match values into separate optional groups with a regex based on character?

3 examples of input:

"13-4h50m2s"
"13-4h2s"
"13-50m"

Preferred code:

const [hours = 0, minutes = 0, seconds = 0] = input.match(some_regexp)

Wanted output {hours,minutes,seconds} for the 3 examples:

{hours: 4, minutes: 50, seconds: 2}
{hours: 4, minutes: 0,  seconds: 2}
{hours: 0, minutes: 50, seconds: 0}

Regex I’ve tried: /(\d+)?[a-z](\d+)?[a-z]?(\d+)?[a-z]?/. But then the second example doesn’t work.

EDIT

Actually, input can be expected to be sorted in the right order (h,m,s).
And it doesn’t matter if the values are stored as strings or numbers.

2 thoughts on “How to match values into separate optional groups with a regex based on character?”

  1. This should answer your question:

    const labelMap = { h: 'hours', m: 'minutes', s: 'seconds' };
    [
      "13-4h50m2s",
      "13-2s4h",
      "13-50m"
    ].forEach((str) => {
      let obj = { hours: 0, minutes: 0, seconds: 0 };
      str.replace(/(\d+)([hms])/g, (m, p1, p2) => {
        obj[labelMap[p2]] = parseInt(p1, 10);
      });
      console.log(JSON.stringify(obj));
    });

    Output:

    {"hours":4,"minutes":50,"seconds":2}
    {"hours":4,"minutes":0,"seconds":2}
    {"hours":0,"minutes":50,"seconds":0}
    

    Notes:

    • the labelMap maps from your input unit to the desired output object key
    • use a string replace that has no return, it’s simply used to iterate over the pattern we want: /(\d+)([hms])/g
    • the replace function composes the object based on the digit and the unit
    Reply
  2. You could match the digits and suffix, and then use Object.fromEntries to turn that result into an object. Use an object initialiser with spread syntax to get 0 for non-populated properties:

    const parse = s =>
        ({h: 0, m: 0, s: 0, ...
            Object.fromEntries(s.match(/\d+[msh]/g).map(m => [m[m.length-1], parseInt(m)]))
        });
    
    let inputs = [
      "13-4h50m2s",
      "13-2s4h",
      "13-50m"
    ];
    
    console.log(inputs.map(parse));

    NB/ This reuses the single letters h, m, s as property names.

    Reply

Leave a Comment