Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<h2>Perl (no eval)</h2> <p><strong>Number of characters: <s>167</s> 106</strong> (see below for the 106 character version)</p> <p>Fully obfuscated function: (167 characters if you join these three lines into one)</p> <pre><code>sub e{my$_="($_[0])";s/\s//g;$n=q"(-?\d++(\.\d+)?+)"; @a=(sub{$1},1,sub{$3*$6},sub{$3+$6},4,sub{$3-$6},6,sub{$3/$6}); while(s:\($n\)|(?&lt;=\()$n(.)$n:$a[7&amp;ord$5]():e){}$_} </code></pre> <p>Clear/deobfuscated version:</p> <pre><code>sub e { my $_ = "($_[0])"; s/\s//g; $n=q"(-?\d++(\.\d+)?+)"; # a regex for "number", including capturing groups # q"foo" in perl means the same as 'foo' # Note the use of ++ and ?+ to tell perl # "no backtracking" @a=(sub{$1}, # 0 - no operator found 1, # placeholder sub{$3*$6}, # 2 - ord('*') = 052 sub{$3+$6}, # 3 - ord('+') = 053 4, # placeholder sub{$3-$6}, # 5 - ord('-') = 055 6, # placeholder sub{$3/$6}); # 7 - ord('/') = 057 # The (?&lt;=... bit means "find a NUM WHATEVER NUM sequence that happens # immediately after a left paren", without including the left # paren. The while loop repeatedly replaces "(" NUM WHATEVER NUM with # "(" RESULT and "(" NUM ")" with NUM. The while loop keeps going # so long as those replacements can be made. while(s:\($n\)|(?&lt;=\()$n(.)$n:$a[7&amp;ord$5]():e){} # A perl function returns the value of the last statement $_ } </code></pre> <p>I had misread the rules initially, so I'd submitted a version with "eval". Here's a version without it.</p> <p>The latest bit of insight came when I realized that the last octal digit in the character codes for <code>+</code>, <code>-</code>, <code>/</code>, and <code>*</code> is different, and that <code>ord(undef)</code> is 0. This lets me set up the dispatch table <code>@a</code> as an array, and just invoke the code at the location <code>7 &amp; ord($3)</code>. </p> <p>There's an obvious spot to shave off one more character - change <code>q""</code> into <code>''</code> - but that would make it harder to cut-and-paste into the shell.</p> <h2>Even shorter</h2> <p><strong>Number of characters: <s>124</s> 106</strong></p> <p>Taking edits by <a href="https://stackoverflow.com/users/20713">ephemient</a> into account, it's now down to 124 characters: (join the two lines into one)</p> <pre><code>sub e{$_=$_[0];s/\s//g;$n=q"(-?\d++(\.\d+)?+)"; 1while s:\($n\)|$n(.)$n:($1,1,$3*$6,$3+$6,4,$3-$6,6,$6&amp;&amp;$3/$6)[7&amp;ord$5]:e;$_} </code></pre> <h2>Shorter still</h2> <p><strong>Number of characters: <s>110</s> 106</strong></p> <p>The ruby solution down below is pushing me further, though I can't reach its 104 characters:</p> <pre><code>sub e{($_)=@_;$n='( *-?[.\d]++ *)'; s:\($n\)|$n(.)$n:(($1,$2-$4,$4&amp;&amp;$2/$4,$2*$4,$2+$4)x9)[.8*ord$3]:e?e($_):$_} </code></pre> <p>I had to give in and use <code>''</code>. That ruby <code>send</code> trick is really useful for this problem.</p> <h2>Squeezing water from a stone</h2> <p><strong>Number of characters: 106</strong></p> <p>A small contortion to avoid the divide-by-zero check.</p> <pre><code>sub e{($_)=@_;$n='( *-?[.\d]++ *)'; s:\($n\)|$n(.)$n:($1,0,$2*$4,$2+$4,0,$2-$4)[7&amp;ord$3]//$2/$4:e?e($_):$_} </code></pre> <p>Here's the test harness for this function:</p> <pre><code>perl -le 'sub e{($_)=@_;$n='\''( *-?[.\d]++ *)'\'';s:\($n\)|$n(.)$n:($1,0,$2*$4,$2+$4,0,$2-$4)[7&amp;ord$3]//$2/$4:e?e($_):$_}' -e 'print e($_) for @ARGV' '1 + 3' '1 + ((123 * 3 - 69) / 100)' '4 * (9 - 4) / (2 * 6 - 2) + 8' '2*3*4*5+99' '2.45/8.5*9.27+(5*0.0023) ' '1 + 3 / -8' </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload