replace-words.js 1.64 KB
const fs = require('fs')
const {Transform} = require('stream')

class ReplaceStream extends Transform {
  // `oldString` is the text to replace; `newString` is the replacement
  constructor(oldString, newString) {
    super({decodeStrings: false}) // take in string chunks
    this.setEncoding('utf8') // output string chunks
    this.oldString = oldString
    this.newString = newString
    // We store the end of the previous chunk
    // in case `oldString` straddles a chunk boundary
    this.remainingChunk = ''
  }

  _transform(chunk, encoding, callback) {
    // Find the strings between occurrences of `oldString`
    const betweenStrings = (this.remainingChunk + chunk).split(this.oldString)
    const lastString = betweenStrings.pop()
    // Write out each `betweenString`,
    // then replace the occurrence of `oldString` with `newString`
    for (const betweenString of betweenStrings) {
      this.push(betweenString, encoding)
      this.push(this.newString, encoding)
    }
    // Keep the last few characters in case `oldString` is split across chunks
    this.push(lastString.slice(0, -this.oldString.length))
    this.remainingChunk = lastString.slice(-this.oldString.length)
    callback()
  }
  // Called after all chunks have been transformed
  _flush(callback) {
    // Write the end of the last chunk
    this.push(this.remainingChunk)
    // As in `_transform()`, `callback` must be called when done
    callback()
  }
}

fs.createReadStream('source.txt', 'utf8')
  .pipe(new ReplaceStream('here', 'there')) // replace 'here' with 'there'
  .pipe(new ReplaceStream('yes', 'no')) // and 'yes' with 'no'
  .pipe(fs.createWriteStream('destination.txt'))