Reputation: 9645
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
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:
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
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
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