Evaluate an expression of minus and tilde

Given an expression matching the regex /^[-~]*x$/, evaluate it in terms of x and output a string matching the regex /^-?x[+-]\d+$/.

For example, the string -~x evaluates to x+1, while the string -~-x evaluates to -x+1, and the string -~-~--x evaluates to x+2.

We start from x and evaluate the string right to left. - negates the term, while ~ converts y to -y-1.

Testcases:

    x  x+0
~x -x-1
-~x  x+1
~-~x -x-2
-~-~x  x+2
--~~x  x+0
~-x  x-1
-~-x -x+1


This is . Shortest answer in bytes wins.

The input/output format is strict. The "x" is mandatory.

• Can we output x+010 instead of x+10 for -~-~-~-~-~-~-~-~-~-~x? It matches the second regex. – user72349 Sep 15 '17 at 18:34
• You can, though I see no reason why. – Leaky Nun Sep 15 '17 at 18:36
• The tilde has different meaning in different languages. You should probably clarify that you intend the Python meaning – Luis Mendo Sep 15 '17 at 19:10
• @LuisMendo read the last sentence of my third paragraph – Leaky Nun Sep 15 '17 at 19:15
• @LeakyNun Ah, sorry, I didn't see that. Anyway, I think it should appear earlier on. The first two paragraphs and part of the third talk about ~ while it hasn't been defined – Luis Mendo Sep 15 '17 at 20:47

Python 2, 4241 39 bytes

lambda s,x=0:'-x%+d'[len(s)%2:]%eval(s)


Try it online!

Retina, 47 44 bytes

+--|~~

((~)|-)*x
$&+$#2
T+-^~.*
~
-
--



Try it online! Edit: Saved 3 bytes thanks to @MartinEnder. Expanation:

+--|~~


((~)|-)*x
$&+$#2


Count the number of ~s which gives us the magnitude of the term.

T+-^~.*


If the first character is a ~ then the term should be negative.

~
-
--


If the number of ~s and -s is odd then the x should be negative.

JavaScript, 59 bytes

x=>['-'[x.length&1]]+'x'+['+'[(x=eval(x.join ))<0^0]]+~~x


Try it online!

• Beat me by 16 secs and 38 bytes. Well done. – Luke Sep 15 '17 at 18:53
• Fails for test cases containing multiple - in a row. (i.e. --~-~x) – Luke Sep 15 '17 at 18:59
• @Luke. I'm not sure what do you mean. My script works for these test cases too. – user72349 Sep 15 '17 at 19:02
• This survives my new testcase :D – Leaky Nun Sep 15 '17 at 19:22
• @ThePirateBay: oops, nvm then... – Luke Sep 15 '17 at 19:27

Perl 5, 75 + 1 (-n)= 76 bytes

map{$y=-$y;$y--if/~/}reverse/-|~/g;printf"%sx%+d",((-1)**y/-~//)=~s/1//r,$y


Try it online!

C (gcc), 69 bytes

a;s;f(char*p){for(a=s=0;*p;a-=*p++%5*~-s)s^=2;printf("-x%+d"+!!s,a);}


Try it online!

-1 byte thanks to @ThePirateBay

Java 8, 186 bytes

s->{s=s.replaceAll("--|~~","");int l,i=(s.length()-(l=(s=s.replaceAll("-~","")).length()))/2,j=l-(s=s.replaceAll("~","")).length();return(j>0?"-"+s+"-"+-~i:s+"+"+i).replaceAll("--","");}


Definitely room for improvements..

Explanation:

Try it here.

s->{                              // Method with String as both parameter and return-type
s=s.replaceAll("--|~~","");     //  Remove all "--" and "~~"
int l,                          //  Temp integer to reduce bytes
i=(s.length()-(l=(s=s.replaceAll("-~","")).length()))/2,
//  Remove all "-~" and save count in i
j=l-(s=s.replaceAll("~","")).length();
//  Remove all remaining "~" and save count in j
return(j>0?                   //  If j is larger than 0:
+s                    //   followed by the remaining s
+-~i                  //   followed by i+1
s                     //   Start with the remaining s
+i                    //   followed by i