7
\$\begingroup\$

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. ;)
\$\endgroup\$
  • 3
    \$\begingroup\$ wait, what's wrong with vim keystrokes? :-) \$\endgroup\$ – John Dvorak Feb 5 '14 at 6:34
  • \$\begingroup\$ do we have to support /[/]/ (character classes containing unescaped slash characters)? Ruby doesn't. \$\endgroup\$ – John Dvorak Feb 5 '14 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 Feb 17 '14 at 10:56
  • \$\begingroup\$ @toothbrush No, you do not. (Sorry for forgetting to reply ;-)) \$\endgroup\$ – Doorknob Feb 17 '14 at 14:12
3
\$\begingroup\$

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
/x){
  if $5 == old.chop then new.chop else $& end
}
| improve this answer | |
\$\endgroup\$
2
\$\begingroup\$

Perl, 122

@a=<>;chomp(($y,$x)=(pop@a,pop@a));$_=join'',@a;s!//.*?\n|/\*.*?\*/|("|'|/)(\\?+.)*?\1\w*|([\w\$]+)!$3eq$x?$y:$&!sge;print

i.e. (semi-ungolfed)

@a=<>;
chomp(($y,$x)=(pop@a,pop@a));
$_=join'',@a;
s!//.*?\n|/\*.*?\*/|("|'|/)(\\?+.)*?\1\w*|([\w\$]+)!$3eq$x?$y:$&!sge;
print

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.

| improve this answer | |
\$\endgroup\$
0
\$\begingroup\$

EcmaScript 6 (138 bytes):

x=(s,o,n)=>s.replace(/\/\/.*?\n|\/\*[\s\S]+?\*\/|('|")(\\\1|[^\1])+?\1|\/(\\u[a-f\d]{4}|\\.|[^\/])+\/[angi]*|[a-z_$][\w$]*/gi,x=>x==o?n:x)

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


It creates a function called x with three parameters:

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

See this JSFiddle for an example.

| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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