1

I have an array of index ranges and a string:

const ranges = [[2,5], [11, 14]]
const str = 'brave new world'

I'm trying to write a function to interpolate and wrap the characters at those ranges.

const magic = (str, ranges, before='<bold>', after='</bold>') => {
  // magic here
  return 'br<bold>ave</bold> new w<bold>orl</bold>d'
}
Paul Floyd
  • 5,530
  • 5
  • 29
  • 43
Louis Grellet
  • 1,083
  • 2
  • 10
  • 14

2 Answers2

1

Assuming your ranges are in the order they need to be applied, then:

  1. Iterate over the ranges.
  2. Add the part of the string previous the start of the range to the result.
  3. Wrap the middle part in the before and after.
  4. Remember which is the last index you processed then repeat 2.-4. for as many ranges there are.
  5. Add the rest of the string after the last range to the result.

const magic = (str, ranges, before='<bold>', after='</bold>') => {
  let result = "";
  let lastIndex = 0;
  
  for(const [start, end] of ranges) {
    result += str.slice(lastIndex, start);
    const wrap = str.slice(start, end);
    result += before + wrap + after;
    lastIndex = end;
  }
  
  result += str.slice(lastIndex);
  
  return result;
}

const ranges = [[2,5], [11, 14]]
const str = 'brave new world'
console.log(magic(str, ranges));
VLAZ
  • 26,331
  • 9
  • 49
  • 67
0

It's easy to write a function that does it for a single range. Write that function, then use reduce to do it repeatedly for each range. In this case, you want to make sure you do the end ranges first so it doesn't change the offset for prior ranges.

If you make sure you go through the ranges in reverse order (sort the array if necessary, or use reduceRight if they're already ordered), then it can be this simple:

// Wraps one range
function wrap(str, [i, j]) {
  const beg = str.substring(0, i),
        mid = str.substring(i, j),
        end = str.substring(j);
  return `${beg}<b>${mid}</b>${end}`;
}
[[2, 5], [11, 14]].reduceRight(wrap, 'brave new world')

So I'd write magic like this:

function magic(str, ranges, b='<bold>', a='</bold>') {
  const wrap = (str, [i, j]) => str.substring(0, i) + b + 
                                str.substring(i, j) + a + str.substring(j);
  return ranges.sort(([i], [j]) => j - i).reduce(wrap, str);
}
Trevor Dixon
  • 23,216
  • 12
  • 72
  • 109