Few questions about Regex

Hello,
I am reading through one MDN page about string.replace() but then I got stuck when trying to read a snippet that is used to showcase for one example.

const p = 'The water boils when it reaches 212F.';

function f2c(x) {
  function convert(str, p1, offset, s) {     
    return ((p1 - 32) * 5/9) + 'C';
  }
  let s = String(x);
  let test = /(-?\d+(?:\.\d*)?)F\b/g;
  return s.replace(test, convert);     
}

console.log(f2c(p))    //  "The water boils when it reaches 100C."

Q1: How do these parameters in convert(str, p1, offset, s) got mapped through s.replace from “test” in s.replace()? how to know what they are mapped to individually?

Q2: What does “(?:.\d*)?” do here? I am not very clear about it. Is it similar to lookahead? Isn’t “-?\d+” sufficient already?

let test = /(-?\d+(?:\.\d*)?)F\b/g;

Thank you.

Answer1: the method replace can either take a string or a callback to replace the matched substring, and in the case you use a callback it already knows how its parameters should be used in the same way you know that about any function you make, e.g., function func (x, y) {return x + y} you know that the x,y will be something that can be added (in this case no exceptions were built into the function so who knows what JavaScript will let you attempt), in the same way the replace callback knows how to use its own parameters because there is a type of function the replace method will expect, and the callback gets it arguments from the string in which you are looking for a match.

Answer2: I have to look up how to use RegEx whenever I use it so I have no idea.

Thank you for the reply.

Yes, I know replace() would look for the matched string as input for the callback, but I don’t quite understand how replace() or the program would decide which parameter specified in convert(str, p1, offset, s) will be mapped to what from the matched string?

More specifically, how does the program know what str, p1, offset, s stands for individually in this convert function?

If this code was submitted for reviews, how do the reviewers understand what these parameters stand for and what is the use of these parameters?

For example, let’s say “212F” is a matched string from regex expression “test”, then what does str, p1, offset, s stand for individually from this matched string “212F”?

const p = 'The water boils when it reaches 212F.';

function f2c(x) {
  function convert(str, p1, offset, s) {
    console.log(
    `str is: ${str}, p1 is: ${p1}, offset is: ${offset}, s is: ${s}     ` 
    )     
    return ((p1 - 32) * 5/9) + 'C';
  }
  let s = String(x);
  let test = /(-?\d+(?:\.\d*)?)F\b/g;
  return s.replace(test, convert);     
}

f2c(p)
//this is what the values are logged as based on the variable p
( str is: 212F, p1 is: 212, offset is: 32, s is: The water boils when it reaches 212F. )  
//this is the return value of the function when called with the variable p  
"The water boils when it reaches 100C."

Thank you, but how did the program realize these strings are assigned to each of these parameters?

str:  212F, 
p1:  212, 
offset:  32, 
s:  The water boils when it reaches 212F. 

From the angle of function convert, it can only see 212F as its input because 212F is the only string that matches regex expr test, right? Then how could “s” be the whole sentence passed by “p”?

The similar questions for other parameters too… my head just couldn’t realize how these value mapping happened from this code…

for the p1 argument that one is based on your capture groups within your regex so the replace callback will expect more p arguments if you have more capture groups, but other than that, just like any function if I have function func (arr, num) {return arr.length + num} the first argument is going to have to be something with a length property, or it’ll throw a type error. Lucky for you the callback knows what the arguments should be based on the match of your string so you don’t have to directly hand the arguments yourself in the same way you don’t have to hand array.prototype.map every single element yourself instead you just do, and I’m going to write this like they made the call back for their replace

const a = [1,2,3];

function callBackForMap (e) {
    return e + 1;
}

a.map(callBackForMap);
(3) [2, 3, 4]

The replace function has access to the whole, it just so happens the first argument was chosen for the matched portion of the string, and its probably ordered that way as it is the whole matched portion you are generally most interested in.

Thank you for the explanations.
I just looked up replace() MDN page and I think this table answers all my puzzles.
I did not know replace() could stipulate what each parameter stands for in the callback function by its order. I thought it could be all defined by ourselves for whatever we want to put in the parameters.
Now this makes all the senses. :sweat_smile:

replace()_callback_parameters