Skip to content

Instantly share code, notes, and snippets.

@andrejewski
Created March 21, 2020 19:32
Show Gist options
  • Save andrejewski/c364118699e97629670629f7a55a0363 to your computer and use it in GitHub Desktop.
Save andrejewski/c364118699e97629670629f7a55a0363 to your computer and use it in GitHub Desktop.
A safer String.prototype.replace
// "substitute" is too hard to type
function sub (str, candidate, replacer) {
/*
NOTE: Using String.prototype.replace is bad because:
1) casting an arbitrary string to a RegExp is unsafe
2) replacement has obscure substitution rules ($ is special)
*/
let match = str.indexOf(candidate)
if (match === -1) {
return str
}
let matches = 0
let newStr = ''
let cursor = 0
while (match !== -1) {
newStr += str.slice(cursor, match) + replacer(matches)
cursor = match + candidate.length
matches++
match = str.indexOf(candidate, cursor)
}
newStr += str.slice(cursor)
return newStr
}
const test = require('ava')
test('sub replace all matches with the replacement', t => {
t.is(
sub('a b a', 'a', () => 'b'),
'b b b'
)
})
test('sub should call replacer with the match index', t => {
t.is(
sub('a a a a', 'a', i => i.toString()),
'0 1 2 3'
)
})
test('sub should not call replacer if there are no matches', t => {
sub('no match', 'zzz', () => t.fail())
t.pass()
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment