roryok
roryok

Reputation: 9645

How to perform an operation on a match in javascript

I'm trying to use javascript (plain js, not jquery or a library) to match items by regex and perform an operation on them.

Basically I'm trying to create a script that converts from Imperial measurements to metric. Here's what I have

    var a = [
            [/([0-9\/]+) (pound[s]?|lb)/ig, 45, "g"],
        ];
    function convert(){
        var t = document.body.innerHTML;
        for(var j = 0; j < a.length; j++){
            var m = t.match(a[j][0]);
            for(var i = 0; i < 1; i++){
                var decimal = eval(m[i].split(' ')[0]);
                t = t.replace(m[i],(decimal * a[j][1]) + a[j][2]);
            }
        }
        document.body.innerHTML = t;
    }

This works, but for certain matches I want to return part of the match. For instance, there's one conversion for a cup of sugar vs a cup of flour, but there are many types of each, so I want to return part of the original string.

If I have

1 cup wholemeal flour

I want to match this with regex along the lines of

/(([0-9\/]+) ((wholemeal |plain |white |strong |self-raising )?flour))/ig

... operate only on the first part, and replace the whole lot with a string including a token, something like

            //match  value   * conversion  + unit    + string token
t - t.replace(m[i], (decimal * a[j][1])    + a[j][2] + m[i][2]);

and come out at the end with

150g wholemeal flour

however, m[i] is a string and I can't find a way to access groups in the match like I could in php or c#

NOTE: I realise that several of these types of flour need separate conversions but I'd still like to know how to do this.

Upvotes: 0

Views: 240

Answers (3)

mihai
mihai

Reputation: 38593

You can't access groups using the match function and a global regex. In this case you would either use exec instead of match, or don't use g and split the text into lines and use match on each line (I'd go for this second approach, but it depends on how your input is organized)

If you're not using a global regex, you can access groups using m[1], m[2] etc. Here's some working code to get you started:

http://jsfiddle.net/TCVDx/5/

var a = [
  [/([0-9\/]+) (cup )?(wholemeal|plain|white|strong|self-raising)? (flour)/i, 45, "g"],
];

function convert(){
  var t = document.getElementById("input").innerHTML;

  for(var j = 0; j < a.length; j++){
    var m = t.match(a[j][0]);
    var decimal = eval(m[0].split(' ')[0]);
    t = (decimal * a[j][1]) + " " + a[j][2] + " " + m[3] + " " + m[4];
  }
  document.getElementById("output").innerHTML = t;
}

Upvotes: 0

d&#39;alar&#39;cop
d&#39;alar&#39;cop

Reputation: 2365

You can do this. It sounds like you want to use the "callback" features of the javascript replace function, something like:

t.replace(m[i],function(match, contents, offset, fullstring){ 
return (decimal * a[j][1])    + a[j][2] + m[i][2])
});

Now with that anonymous function you have the power to operate more precisely on the matched groups.

If that doesn't help, are you aware of the '$1-9' constructs? e.g.

t.replace(/(([0-9\/]+) ((wholemeal |plain |white |strong |self-raising )?flour))/ig,'$1');

This will replace each group with only what's in the first bracketed group '(xxx)'. These however are standard in PHP too. You may further perform what operations you want on the '$1' string.

I hope it helps! - if I missed the point please comment to clarify if you want.

Upvotes: 0

Loamhoof
Loamhoof

Reputation: 8293

You can't access your groups because of the "g" modifier (still don't know why you can't while JavaScript fully supports nested structures...).

What you can do to have the same effect, is loop through your string thanks to the Regex#exec method. So, instead of doing:

myString.match(myRegex);

where myRegex has the "g" modifier. You can do that:

var match;
while(match = myRegex.exec(myString)) {
  // do stuff here...
}

Thanks to the lastIndex property of the Regex object, you'll loop through your string and finally returns null.

Upvotes: 2

Related Questions