Spot the bug - #135: Text Parser Log

Why does my vampire detector miss identical counts of bats?

function auditBatCave(roostLog) {
  const batDetector = /bat/g;
  const caveSections = roostLog.split('---');
  const report = [];

  for (const section of caveSections) {
    const batMatches = [];
    let match;
    
    while ((match = batDetector.exec(section)) !== null) {
      batMatches.push(match.index);
    }

    report.push({
      sectionText: section.trim(),
      batCount: batMatches.length,
      positions: batMatches
    });
  }

  return report;
}

const sampleLog = "bat bat bat --- bat bat bat";
console.log(auditBatCave(sampleLog));

Reply with what is broken and how you would fix it.

The bug is that the regex has the g flag, so batDetector keeps its lastIndex between sections.

After the first section finishes, lastIndex is already at the end of that string. When exec() is called on the next section, it starts from that old index and can miss matches.

The simple fix is to reset lastIndex before processing each section:

for (const section of caveSections) {
  batDetector.lastIndex = 0;

  const batMatches = [];
  let match;

  while ((match = batDetector.exec(section)) !== null) {
    batMatches.push(match.index);
  }

  // ...
}

Then both sections correctly report 3 bats.

Nice catch on the g flag behavior. That’s a classic one that bites people. We’ll post the full answer later today.

The g flag always trips people up with exec. It’s a mutable state thing that’s easy to forget.

Interesting