How to use a counter in a function without returning content

I want to write a function similar to this code. I know that this is exact code is not going to work because counter needs to be either state or counter type but that also requires using context blocks. I didnt get that to work either because str.replace() only accepts a function that returns a str Not content.

Is there any solution to get this to work using str.replace()?


#let replace(string) = {
  let counter = 0
  
  return string.replace("a", match => {
    if calc.even(counter) {
      counter += 1
      return "a"
    } else {
      counter += 1
      return "b"
    }
  })  
}

#let result = replace("aaa") // Should return "aba"

Welcome! I don’t think this is possible with string.replace, exactly for the reasons you list. The best way to do this is to create a custom function that essentially builds an entirely new string.

If you are only replacing single characters, you can do this with e.g. array.fold:

#let replace(string) = {
  return string.clusters().fold(("", 0), ((acc, counter), char) => {
    if char != "a" {
      return (acc + char, counter)
    }
    if calc.even(counter) {
      return (acc + char, counter + 1)
    }
    return (acc + "b", counter + 1)
  }).first()
}
1 Like