PaningningPH
PaningningPH

Reputation: 59

How do I extract the coefficients and variables of an algebraic expression in an array using regex in javascript?

I want to store the algebraic parts in an array. Currently, I have this but it's not fully working.

function exp(term) {
    var container = [];
    if (term[0] === '-') {
        container[0] = '-1';
        container[1] = term.match(/([0-9]+)/g)[0];
        container[2] = term.match(/([a-zA-Z]+)/g)[0];
    } 
    else {
        container[0] = '0';
        container[1] = term.match(/([0-9]+)/g)[0];
        container[2] = term.match(/([a-zA-Z]+)/g)[0];
    }
    return container;
}

console.log(exp('-24mn'));    //should output ['-1', '24', 'mn']
console.log(exp('-100BC'));   //should output ['-1', '100', 'BC']
console.log(exp('100BC'));    //should output ['0', '100', 'BC']
console.log(exp('100'));      //should output ['0', '100', '']
console.log(exp('BC'));       //should output ['0', '0', 'BC']
console.log(exp('-bC'));      //should output ['-1', '0', 'bC']
console.log(exp('-100'));     //should output ['-1', '100', '']

But if possible, what I really want is an array of length 2 only, containing the coefficient and the variables like:

console.log(exp('-24mn'));    //should output ['-24', 'mn']
console.log(exp('-100BC'));   //should output ['-100', 'BC']
console.log(exp('100BC'));    //should output ['100', 'BC']
console.log(exp('100'));      //should output ['100', '']
console.log(exp('BC'));       //should output ['0', 'BC']
console.log(exp('-bC'));      //should output ['-1', 'bC']
console.log(exp('-100'));     //should output ['-100', '']

I only did the array of length 3 approach because I don't know how to deal with a case where there's only a negative sign followed by variables like '-bC' and also only variables like 'BC'. Any help will be greatly appreciated. Thanks in advance!

Upvotes: 1

Views: 133

Answers (2)

The fourth bird
The fourth bird

Reputation: 163457

The pattern that you tried, contains all optional parts which could also match an empty string.

You could use an alternation with 4 capture groups. Then return an array with either group 1 and 2, or an array with group 3 and 4.

The value of 0 and -1 can be determined by checking if group 3 (denoted as m[3] in the code) exists.

^(-?\d+)([a-z]*)|(-)?([a-z]+)$
  • ^ Start of string
  • (-?\d+) Capture group 1 Match optional - and 1+ digits
  • ([a-z]*) Capture group 2 Capture optional chars a-zA-Z
  • | Or
  • (-)?Optional capture group 3 Match -
  • ([a-z]+) Capture group 4 Match 1+ chars a-zA-Z
  • $ End of string

Regex demo

Example using a case insensitive match using the /i flag:

const regex = /^(-?\d+)([a-z]*)|(-)?([a-z]+)$/gi;
const exp = str => Array.from(
  str.matchAll(regex), m => m[4] ? [m[3] ? -1 : 0, m[4]] : [m[1], m[2]]
);
[
  "-24mn",
  "-100BC",
  "100BC",
  "100",
  "BC",
  "-bC",
  "-100",
  ""
].forEach(s =>
  console.log(exp(s))
);

Upvotes: 1

thabs
thabs

Reputation: 613

Your can use groups to capture the two parts and add some additional logic for handling cases where the number is not present in the input:

function exp(term) {
    const matches = term.match(/(-?[0-9]*)([a-zA-Z]*)/);
    return [convertNumMatch(matches[1]), matches[2]];
}

function convertNumMatch(numMatch) {
    if (!numMatch)
        return '0';
    else if (numMatch === '-')
        return '-1';
    else
        return numMatch;
}

Upvotes: 1

Related Questions