Reputation: 1369
Currently, I use this code to total parenthetical values in a string...
if ((string.match(/\((\d+)\)/g)||[]).length > 0) {
var total = 0;
string.replace(/\((\d+)\)/g, function(outerValue, innerValue){
if (!isNaN(innerValue.toString().trim())) {
total = total + Number(innerValue.toString().trim());
}
});
value = total;
}
...so the string...
(2) dark chocolate, (2) milk chocolate, and (1) white chocolate
...totals 5.
Not willing to leave well-enough alone, I thought it would be cool if I could be a bit fancier and interpret different types of operations, so that someone could write.
(2) dark + (2) milk - (1) white
-or-
(2) dark and (2) milk minus (1) white
So I changed my code to...
if ((string.match(/\((\d+)\)/g)||[]).length > 0) {
var total = 0;
string.replace(/^\((\d+)\)|and\s\((\d+)\)|plus\s\((\d+)\)|\+\s\((\d+)\)/g, function(outerValue, innerValue){
if (!isNaN(innerValue.toString().trim())) {
total = total + Number(innerValue.toString().trim());
}
});
value = total;
}
...but the innerValue returns as undefined. I am able to extract the values when I test with the validator in regex101.com, but not in Javascript.
What am I doing incorrectly?
p.s. Obviously, my code is not complete (in addition to being wrong). Ultimately, I would list all of the operator possibilities (e.g., "+", "plus", "and", "less", "minus", "-", etc.) and would examine the string in outerValue to determine the operator. And, of course, I need to write the logic for commas within a sentence (e.g., allow a single operator in the sentence and apply the operation to each item).
Upvotes: 1
Views: 85
Reputation: 1369
chiliNUT's explanation was extremely helpful, as was his subsequent suggestion in his reply. Inspired to explore some variations, I ended up coding it as follows:
if ((string.match(/\((\d+)\)/g)||[]).length > 0) {
var total = 0;
string.match(/^\((\d+)\)|,\s+\((\d+)\)|and\s+\((\d+)\)|plus\s+\((\d+)\)|\+\s+\((\d+)\)|\-\s+\((\d+)\)|minus\s+\((\d+)\)|less\s+\((\d+)\)|subtract\s+\((\d+)\)|times\s+\((\d+)\)|multiply\s+\((\d+)\)|x\s+\((\d+)\)|\*\s+\((\d+)\)/g).forEach(function(element, index){
element.replace(/\((\d+)\)/g, function(m, p){
if (!isNaN(p.toString().trim())) {
p = Number(p);
if (element.match(/^(minus|less|substract|\-)/g)) {
total = total - p;
}
else if (element.match(/^(times|multiply|x|\*)/g)) {
total = total * p;
}
else {
total = total + p;
}
}
});
});
}
I'm sure there's a more efficient way, but for my deepest RegEx dive thus far, and given that it actually works, I figure it's a good start.
Upvotes: 0
Reputation: 19573
Your argument names (outerValue, innerValue)
aren't really accurate. The arguments to the replace function are
function replace(match, p1, p2, ..., pn, offset, string)
So you have
p1 p2 p3 p4
| | | |
/^\((\d+)\)|and\s\((\d+)\)|plus\s\((\d+)\)|\+\s\((\d+)\)/g
|
match
So when you run (2) dark and (2) milk minus (1) white
through your replacer function:
The first match "(2)" has p1=2
since it corresponds to the 1st parenthetical set in your regex, ie, in the first or group. You then have p2=undefined, p3=undefined, p4=undefined
.
The next match "and (2)" has p1=undefined
since this matches up with the 2nd or group in your regex, so p1=undefined, p2=2, p3=undefined, p4=undefined
Upvotes: 2
Reputation: 23317
I would suggest to build a add a parser that would interpret the string. I'd user regexps to extract tokens from text ((1)
=> 1
, -
=> -
) and pass it to the parser. It would keep track of values and operators and perform calculations.
This thread may be related: https://stackoverflow.com/a/380487/580346
Upvotes: 0