Вычисление строки простых математических выражений

Perl (без оценки)

Количество символов: 167 106 (версия для 106 символов parser см. ниже)

Полностью запутанная mathematics функция: (167 символов, если mathematics вы объедините эти три строки parse в одну)

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\)|(?<=\()$n(.)$n:$a[7&ord$5]():e){}$_}

Чистая / деобфускированная parsers версия:

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 (?<=... 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\)|(?<=\()$n(.)$n:$a[7&ord$5]():e){}

  # A perl function returns the value of the last statement
  $_
}

Изначально я неправильно arithmetic прочитал правила, поэтому mathematical отправил версию с eval. Вот infix-notation версия без него.

Последний parser раз я понял, что последняя parser восьмеричная цифра в кодах parser символов для +, -, / и * отличается, и text-parsing что ord(undef) - это 0. Это позволяет infix-notation мне настроить таблицу отправки math @a как массив и просто вызвать arithmetic код в местоположении 7 & ord($3).

Есть parser очевидное место, где можно parsers сбрить еще один символ - заменить text-parsing q"" на '', - но это затруднит parse вырезание и вставку в оболочку.

Еще короче

Количество символов: 124 106

С mathematics учетом изменений, внесенных infix ephemient, теперь он сократился до math 124 символов: (объедините parse две строки в одну)

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&&$3/$6)[7&ord$5]:e;$_}

Еще короче

Количество символов: 110 106

Решение parsers с рубином, приведенное ниже, подталкивает parse меня еще дальше, хотя я не infix могу охватить его 104 символа:

sub e{($_)=@_;$n='( *-?[.\d]++ *)';
s:\($n\)|$n(.)$n:(($1,$2-$4,$4&&$2/$4,$2*$4,$2+$4)x9)[.8*ord$3]:e?e($_):$_}

Мне mathematical пришлось уступить и использовать mathematics ''. Трюк с рубином send действительно parsing полезен для решения этой infix-notation проблемы.

Выжимание воды из камня

Количество символов: 106

Небольшое искажение, чтобы text-parsing избежать проверки деления arithmetic на ноль.

sub e{($_)=@_;$n='( *-?[.\d]++ *)';
s:\($n\)|$n(.)$n:($1,0,$2*$4,$2+$4,0,$2-$4)[7&ord$3]//$2/$4:e?e($_):$_}

Вот тестовая программа text-parsing для этой функции:

perl -le 'sub e{($_)=@_;$n='\''( *-?[.\d]++ *)'\'';s:\($n\)|$n(.)$n:($1,0,$2*$4,$2+$4,0,$2-$4)[7&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'

math

parsing

code-golf

text-parsing

infix-notation

2022-05-10T19:39:03+00:00