Your challenge today is to refactor JavaScript code. You will take three strings as input; a JavaScript string, a old variable name, and the name you want to refactor it to. For example, an input of

"var x = 100; alert(x);", "x", "num"

Will output

"var num = 100; alert(num);"

Here's a more advanced test case:

"var gb = 1; var g = bg = 2; gb = bg = g = function(gg) { alert(gb); };
var str = 'g gb bg gg'; var regexp = /gb gb gb/g; //comment gb gb g g
/*gb gb g g*/", "gb", "aaa"

It should output

var aaa = 1; var g = bg = 2; aaa = bg = g = function(gg) { alert(aaa); };
var str = 'g gb bg gg'; var regexp = /gb gb g g/g; //comment gb gb g g
/*gb gb g g*/

And the same JS input with the other arguments "g", "aaa" should output

var gb = 1; var aaa = bg = 2; gb = bg = aaa = function(gg) { alert(gb); };
var str = 'g gb bg gg'; var regexp = /gb gb gb/g; //comment gb gb g g
/*gb gb g g*/

Here is one last much more complicated test case:

var g = 1; "g\"g"; "g'"; g; '"g\'g"g'; /g"\/*\//g; g; "// /*"; g; "*/"

It should output, with other parameters "g" and "a", this:

var a = 1; "g\"g"; "g'"; a; '"g\'g"g'; /g"\/*\//g; a; "// /*"; a; "*/"

(sidenote: I really like /g"\/*\//g; I think that's just evil :D)

Full specification:

  • For simplicity, you may ignore scope. Ex. "var a=1; function(){var a=2;}; var o={a: 3}", "a", "b" can output var b=1; function(){var b=2;}; var o={b: 3}.
  • Text in strings ('...' and "..."), regexps and their modifiers (/.../...), and comments (//...\n and /*...*/) must not be modified.
  • Also for simplicity, a valid identifier is one that starts with a letter, dollar sign, or underscore, and the rest of the characters are letters, numbers, dollar signs, or underscores.
  • You may assume that the input contains no syntax errors.
  • This is , so the shortest code in bytes will win.
  • If you use network access, all bytes downloaded from the network count towards your score.
  • You must use an actual programming language. No IDE solutions, like emacs or vim keystrokes. ;)
  • 3
    \$\begingroup\$ wait, what's wrong with vim keystrokes? :-) \$\endgroup\$ Commented Feb 5, 2014 at 6:34
  • \$\begingroup\$ do we have to support /[/]/ (character classes containing unescaped slash characters)? Ruby doesn't. \$\endgroup\$ Commented Feb 5, 2014 at 8:46
  • \$\begingroup\$ Asking the same as @JanDvorak above: do we need to support /[/]/ (character classes containing unescaped slash characters)? Most languages with built-in support for regular expressions don't; however, JavaScript does. \$\endgroup\$
    – Toothbrush
    Commented Feb 17, 2014 at 10:56
  • \$\begingroup\$ @toothbrush No, you do not. (Sorry for forgetting to reply ;-)) \$\endgroup\$
    – Doorknob
    Commented Feb 17, 2014 at 14:12

3 Answers 3


Ruby, 134 (113?) characters

*c,o,n=*$<;puts (c*?\n).gsub(/('|")((\\?+.)*?)\1|\/\*[\s\S]*?\*\/|\/\/.*|\/(\[\g<2>\]|\g<2>)+?\/\w*|([\w$]+)/){$5==o.chop&&n.chop||$&}

Unicode is not supported. If Unicode identifiers are to be supported, replace \w with [[:word:]] and [\w$] with ([[:word:]]|\$) (and adjust the backreferences).

If unescaped slashes inside regexp literals (such as /[/]/) don't need to be supported, we can handle them together with string literals (116 characters). This also gives us string flags:

*c,o,n=*$<;puts (c*?\n).gsub(/\/\*[\s\S]*?\*\/|\/\/.*|('|"|\/)((\\?+.)*?)\1\w*|([\w$]+)/){$4==o.chop&&n.chop||$&}

Ungolfed version:

*code, old, new = *$<

puts code.join("\n").gsub (/
     ('|")((\\?+.)*?)\1           #strings
   | \/\*[\s\S]*?\*\/             #multiline comments
   | \/\/.*                       #single-line comments
   | \/(\[\g<2>\]|\g<2>)+?\/\w*   #regexes
   | ([\w$]+)                     #identifiers and keywords
  if $5 == old.chop then new.chop else $& end

Perl, 122


i.e. (semi-ungolfed)


practically the same as Ruby's short version answer (except I didn't knew about possessive quantifiers trick and my first take was slightly longer). Regexp is shorter, but 'I/O' part spoils everything (Perl can't do (@a,$x,$y)=<>), and my assumption (the same I see in Ruby's, if I'm not mistaken) was we feed JS string line by line through STDIN, followed by 'old name' and 'new name' on separate lines.


ECMAScript 6, 136 bytes


Runs fine on any recent version of Firefox/Google Chrome.

It creates a function with three parameters:

  1. The code
  2. The old variable name
  3. The new variable name

See this JSFiddle for an example.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.