评估一串简单的数学表达式

Nol*_*rin 76 math parsing code-golf infix-notation text-parsing

挑战

这是挑战(我自己的发明,但如果以前出现在网络的其他地方,我不会感到惊讶).

编写一个函数,该函数采用单个参数,该参数是简单数学表达式的字符串表示形式,并将其作为浮点值进行计算."简单表达"可以包括以下任何一种:正十进制数或负十进制数,+,-,*,/,(,).表达式使用(正常)中缀表示法.操作员应按其出现的顺序进行评估,即不像BODMAS中那样进行 评估,但当然应该正确观察括号.该函数应该为此表单的任何可能表达式返回正确的结果.但是,该函数不必处理格式错误的表达式(即语法错误的表达式).

表达的例子:

1 + 3 / -8                            = -0.5       (No BODMAS)
2*3*4*5+99                            = 219
4 * (9 - 4) / (2 * 6 - 2) + 8         = 10
1 + ((123 * 3 - 69) / 100)            = 4
2.45/8.5*9.27+(5*0.0023)              = 2.68...
Run Code Online (Sandbox Code Playgroud)

规则

我预计会有某种形式的"作弊"/狡猾,所以请让我预先反对它!通过作弊,我指的是eval在动态语言(如JavaScript或PHP)中使用或等效函数,或者同时编译和执行代码.(我认为我的"没有BODMAS"的规格几乎可以保证这一点.)除此之外,没有任何限制.我在这里预计会有一些Regex解决方案,但不仅仅是这样,我们会感到很高兴.

现在,我主要对C#/ .NET解决方案感兴趣,但是任何其他语言都是完全可以接受的(特别是F#和Python用于功能/混合方法).我还没有决定我是否会接受最短或最巧妙的解决方案(至少对于语言而言)作为答案,但我欢迎任何语言的任何形式的解决方案,除了我刚才禁止的!

我的解决方案

我现在在这里发布了我的C#解决方案(403个字符).更新: 我的新解决方案294个字符处显着击败旧的解决方案,借助一些可爱的正则表达式!我怀疑这会被一些语言轻松打败,语法较轻(特别是功能/动态),并且已被证明是正确的,但我很好奇是否有人能在C#中击败它.

更新

我已经看到了一些非常狡猾的解决方案.感谢所有发布过的人.虽然我还没有对它们中的任何一个进行测试,但我会相信人们并假设他们至少可以使用所有给定的例子.

仅仅为了注释,重新入门(即线程安全)不是函数的要求,尽管它是一个奖励.


格式

请以下列格式发布所有答案,以便于比较:

语言

字符数:???

完全混淆的功能:

(code here)
Run Code Online (Sandbox Code Playgroud)

清除/半混淆功能:

(code here)
Run Code Online (Sandbox Code Playgroud)

关于算法/聪明的快捷方式的任何注释.


Ski*_*izz 44

汇编

427个字节

混淆,用优秀的A86组装成.com可执行文件:

dd 0db9b1f89h, 081bee3h, 0e8af789h, 0d9080080h, 0bdac7674h, 013b40286h
dd 07400463ah, 0ccfe4508h, 08ce9f675h, 02fc8000h, 013b0057eh, 0feaac42ah
dd 0bedf75c9h, 0ba680081h, 04de801h, 04874f73bh, 04474103ch, 0e8e8b60fh
dd 08e8a003fh, 0e880290h, 0de0153h, 08b57e6ebh, 0d902a93eh, 046d891dh
dd 08906c783h, 05f02a93eh, 03cffcee8h, 057197510h, 02a93e8bh, 08b06ef83h
dd 05d9046dh, 02a93e89h, 03bc9d95fh, 0ac0174f7h, 074f73bc3h, 0f3cac24h
dd 0eed9c474h, 0197f0b3ch, 07cc4940fh, 074f73b09h, 0103cac09h, 0a3ce274h
dd 0e40a537eh, 0e0d90274h, 02a3bac3h, 021cd09b4h, 03e8b20cdh, 0ff8102a9h
dd 0ed7502abh, 0474103ch, 0e57d0b3ch, 0be02a3bfh, 014d903a3h, 0800344f6h
dd 02db00574h, 0d9e0d9aah, 0d9029f2eh, 0bb34dfc0h, 08a0009h, 01c75f0a8h
dd 020750fa8h, 0b0f3794bh, 021e9aa30h, 0de607400h, 08802990eh, 0de07df07h
dd 0c392ebc1h, 0e8c0008ah, 0aa300404h, 0f24008ah, 04baa3004h, 02eb0ee79h
dd 03005c6aah, 0c0d90ab1h, 0e9defcd9h, 02a116deh, 0e480e0dfh, 040fc8045h
dd 0ede1274h, 0c0d90299h, 015dffcd9h, 047300580h, 0de75c9feh, 0303d804fh
dd 03d80fa74h, 04f01752eh, 0240145c6h, 0dfff52e9h, 0d9029906h, 0f73b025fh
dd 03caca174h, 07fed740ah, 0df07889ah, 0277d807h, 047d9c1deh, 0990ede02h
dd 025fd902h, 03130e0ebh, 035343332h, 039383736h, 02f2b2d2eh, 02029282ah
dd 0e9000a09h, 07fc9f9c1h, 04500000fh, 0726f7272h
db 024h, 0abh, 02h
Run Code Online (Sandbox Code Playgroud)

编辑:未经过模糊处理的来源:

        mov [bx],bx
        finit
        mov si,81h
        mov di,si
        mov cl,[80h]
        or cl,bl
        jz ret
    l1:
        lodsb
        mov bp,d1
        mov ah,19
    l2:
        cmp al,[bp]
        je l3
        inc bp
        dec ah
        jne l2
        jmp exit
    l3:
        cmp ah,2
        jle l4
        mov al,19
        sub al,ah
        stosb
    l4:
        dec cl
        jnz l1
        mov si,81h
        push done

    decode:
    l5:
        call l7
    l50:
        cmp si,di
        je ret
        cmp al,16
        je ret
        db 0fh, 0b6h, 0e8h ; movzx bp,al
        call l7
        mov cl,[bp+op-11]
        mov byte ptr [sm1],cl
        db 0deh
    sm1:db ?
        jmp l50

    open:
        push di
        mov di,word ptr [s]
        fstp dword ptr [di]
        mov [di+4],bp
        add di,6
        mov word ptr [s],di
        pop di
        call decode
        cmp al,16
        jne ret
        push di
        mov di,word ptr [s]
        sub di,6
        mov bp,[di+4]
        fld dword ptr [di]
        mov word ptr [s],di
        pop di
        fxch st(1)
        cmp si,di
        je ret
        lodsb
        ret



    l7: cmp si,di
        je exit
        lodsb
        cmp al,15
        je open
        fldz
        cmp al,11
        jg exit
        db 0fh, 94h, 0c4h ; sete ah 
        jl l10
    l9:
        cmp si,di
        je l12
        lodsb
        cmp al,16
        je ret
    l10:
        cmp al,10
        jle l12i

    l12:
        or ah,ah
        je l13
        fchs
    l13:
        ret

    exit:
        mov dx,offset res
        mov ah,9
        int 21h
        int 20h

    done:
        mov di,word ptr [s]
        cmp di,(offset s)+2
        jne exit
        cmp al,16
        je ok
        cmp al,11
        jge exit
    ok:
        mov di,res
        mov si,res+100h
        fst dword ptr [si]
        test byte ptr [si+3],80h
        jz pos
        mov al,'-'
        stosb
        fchs
    pos:
        fldcw word ptr [cw]
        fld st(0)
        fbstp [si]
        mov bx,9
    l1000:
        mov al,[si+bx]
        test al,0f0h
        jne startu
        test al,0fh
        jne startl
        dec bx
        jns l1000
        mov al,'0'
        stosb
        jmp frac

    l12i:
        je l11
        fimul word ptr [d3]
        mov [bx],al
        fild word ptr [bx]
        faddp
        jmp l9
        ret

    startu:
        mov al,[si+bx]
        shr al,4
        add al,'0'
        stosb
    startl:
        mov al,[si+bx]
        and al,0fh
        add al,'0'
        stosb
        dec bx
        jns startu

    frac:
        mov al,'.'
        stosb
        mov byte ptr [di],'0'
        mov cl,10
        fld st(0)
        frndint
    frac1:  
        fsubp st(1)
        ficom word ptr [zero]
        fstsw ax
        and ah,045h
        cmp ah,040h
        je finished
        fimul word ptr [d3]
        fld st(0)
        frndint
        fist word ptr [di]
        add byte ptr [di],'0'
        inc di
        dec cl
        jnz frac1

    finished:   
        dec di
        cmp byte ptr [di],'0'
        je finished
        cmp byte ptr [di],'.'
        jne f2
        dec di
    f2:
        mov byte ptr [di+1],'$'
    exit2:
        jmp exit


    l11:
        fild word ptr [d3]
        fstp dword ptr [bx+2]
    l111:
        cmp si,di
        je ret
        lodsb
        cmp al,10
        je exit2
        jg ret
        mov [bx],al
        fild word ptr [bx]
        fdiv dword ptr [bx+2]
        faddp
        fld dword ptr [bx+2]
        fimul word ptr [d3]
        fstp dword ptr [bx+2]
        jmp l111


    d1: db '0123456789.-+/*()', 32, 9
    d3: dw 10
    op: db 0e9h, 0c1h, 0f9h, 0c9h
    cw: dw 0f7fh
    zero: dw 0
    res:db 'Error$'
    s:  dw (offset s)+2
Run Code Online (Sandbox Code Playgroud)


Dan*_*tin 36

Perl(没有评估)

字符数:167 106(106字符版本见下文)

完全混淆的功能:(如果将这三行连接成一个,则为167个字符)

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){}$_}
Run Code Online (Sandbox Code Playgroud)

清除/反混淆版本:

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
  $_
}
Run Code Online (Sandbox Code Playgroud)

我最初误读了规则,所以我提交了一个带有"eval"的版本.这是没有它的版本.

当我意识到字符中的最后一个八进制数字代码为+,-/,并且*是不同的时,最新的一点见解就出现了.ord(undef)这让我可以将调度表设置@a为一个数组,只需调用代码即可.位置7 & ord($3).

有一个显而易见的地方可以削减一个角色 - q""换成''- 但这会让你更难切入并粘贴到外壳中.

更短

字符数:124 106

考虑到ephemient的编辑,它现在已经减少到124个字符:(将两行合并为一行)

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;$_}
Run Code Online (Sandbox Code Playgroud)

还是更短

字符数:110 106

下面的红宝石解决方案正在推动我,尽管我无法达到它的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($_):$_}
Run Code Online (Sandbox Code Playgroud)

我不得不放弃并使用''.这个红宝石send技巧对这个问题非常有用.

从石头上挤水

字符数:106

一个小的扭曲,以避免零除检查.

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

这是此功能的测试工具:

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'
Run Code Online (Sandbox Code Playgroud)

  • perl的.是.生病. (15认同)
  • @Epaga,别担心,我得到了你的错字:perl.是.真棒. (7认同)
  • 可爱的小Perl是多么可怕,我编辑了我的答案,以保持它最小的Ruby实现,并在170个字符的空间.但124?好肉汁! (3认同)

fin*_*nnw 29

红宝石

字符数:103

N='( *-?[\d.]+ *)'
def e x
x.sub!(/\(#{N}\)|#{N}([^.\d])#{N}/){$1or(e$2).send$3,e($4)}?e(x):x.to_f
end
Run Code Online (Sandbox Code Playgroud)

这是The Wicked Flea解决方案的非递归版本.括号内的子表达式是自下而上而不是自上而下的评估.

编辑:将'while'转换为条件+尾递归已经保存了几个字符,因此它不再是非递归的(尽管递归在语义上是不必要的.)

编辑:借用Daniel Martin关于合并正则表达式的想法可以节省另外11个字符!

编辑:那个递归比我最初想的更有用!如果恰好包含一个数字,则x.to_f可以重写为.e(x)x

编辑:使用' or'而不是' ||'允许删除一对括号.

长版:

# Decimal number, as a capturing group, for substitution
# in the main regexp below.
N='( *-?[\d.]+ *)'

# The evaluation function
def e(x)
  matched = x.sub!(/\(#{N}\)|#{N}([^\d.])#{N}/) do
    # Group 1 is a numeric literal in parentheses.  If this is present then
    # just return it.
    if $1
      $1
    # Otherwise, $3 is an operator symbol and $2 and $4 are the operands
    else
      # Recursively call e to parse the operands (we already know from the
      # regexp that they are numeric literals, and this is slightly shorter
      # than using :to_f)
      e($2).send($3, e($4))
      # We could have converted $3 to a symbol ($3.to_s) or converted the
      # result back to string form, but both are done automatically anyway
    end
  end
  if matched then
    # We did one reduction. Now recurse back and look for more.
    e(x)
  else
    # If the string doesn't look like a non-trivial expression, assume it is a
    # string representation of a real number and attempt to parse it
    x.to_f
  end
end
Run Code Online (Sandbox Code Playgroud)


Ski*_*izz 29

C(VS2005)

字符数:1360

滥用预处理器和警告以获得有趣的代码布局(向下滚动以查看):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define b main
#define c(a) b(a,0)
#define d -1
#define e -2
#define g break
#define h case
#define hh h
#define hhh h
#define w(i) case i
#define i return
#define j switch
#define k float
#define l realloc
#define m sscanf
#define n int _
#define o char
#define t(u) #u
#define q(r) "%f" t(r)  "n"
#define s while
#define v default
#define ex exit
#define W printf
#define x fn()
#define y strcat
#define z strcpy
#define Z strlen

char*p    =0    ;k    *b    (n,o**    a){k*f
;j(_){    hh   e:     i*    p==40?    (++p,c
(d        ))  :(      f=        l(        0,
4)        ,m (p       ,q        (%        ),
f,&_),    p+=_        ,f       );        hh
d:f=c(    e);s        (1      ){        j(
    *p    ++ ){       hh     0:        hh
    41    :i  f;      hh    43        :*
f+=*c(    e)   ;g     ;h    45:*f=    *f-*c(
e);g;h    42    :*    f=    *f**c(    e);g;h

47:*f      /=*c      (e);     g;   v:    c(0);}
}w(1):    if(p&&    printf    (q  ((     "\\"))
,*  c(    d)  ))    g;  hh    0: ex      (W
(x  ))    ;v  :p    =(        p?y:       z)(l(p
,Z(1[     a]  )+    (p        ?Z(p           )+
1:1))     ,1  [a    ])  ;b    (_ -1          ,a
+1  );    g;  }i    0;};fn    ()  {n     =42,p=
43  ;i     "Er"      "ro"     t(   r)    "\n";}
Run Code Online (Sandbox Code Playgroud)


eph*_*ent 25

哈斯克尔

字符数:182

没有尝试聪明,只是一些压缩:4行,312字节.

import Data.Char;import Text.ParserCombinators.Parsec
q=either(error.show)id.runParser t id"".filter(' '/=);t=do
s<-getState;a<-fmap read(many1$oneOf".-"<|>digit)<|>between(char '('>>setState id)(char ')'>>setState s)t
option(s a)$choice(zipWith(\c o->char c>>return(o$s a))"+-*/"[(+),(-),(*),(/)])>>=setState>>t
Run Code Online (Sandbox Code Playgroud)

现在,真正进入高尔夫精神,3线和182字节:

q=snd.(`e`id).filter(' '/=)
e s c|[(f,h)]<-readsPrec 0 s=g h(c f);e('(':s)c=g h(c f)where(')':h,f)=e s id
g('+':h)=e h.(+);g('-':h)=e h.(-);g('*':h)=e h.(*);g('/':h)=e h.(/);g h=(,)h
Run Code Online (Sandbox Code Playgroud)

分解:

-- Strip spaces from the input, evaluate with empty accumulator,
-- and output the second field of the result.
q :: String -> Double
q = snd . flip eval id . filter (not . isSpace)

-- eval takes a string and an accumulator, and returns
-- the final value and what’s left unused from the string.
eval :: (Fractional a, Read a) => String -> (a -> a) -> (String, a)

-- If the beginning of the string parses as a number, add it to the accumulator,
-- then try to read an operator and further.
eval str accum | [(num, rest)] <- readsPrec 0 str = oper rest (accum num)

-- If the string starts parentheses, evaluate the inside with a fresh
-- accumulator, and continue after the closing paren.
eval ('(':str) accum = oper rest (accum num) where (')':rest, num) = eval str id

-- oper takes a string and current value, and tries to read an operator
-- to apply to the value.  If there is none, it’s okay.
oper :: (Fractional a, Read a) => String -> a -> (String, a)

-- Handle operations by giving eval a pre-seeded accumulator.
oper ('+':str) num = eval str (num +)
oper ('-':str) num = eval str (num -)
oper ('*':str) num = eval str (num *)
oper ('/':str) num = eval str (num /)

-- If there’s no operation parsable, just return.
oper str num = (str, num)
Run Code Online (Sandbox Code Playgroud)

  • 我认为你过分惩罚了你的人物数量.问题是String-> Double函数,所以你应该通过替换"main = interact $ show"来计算字符数.对于"q =",对于另外17个字符,将您的计数设置为209. (2认同)

Jas*_*son 25

Visual Basic.NET

字符数:9759

我自己更喜欢投球手.

注意:不考虑嵌套括号.此外,未经测试,但我很确定它的工作原理.

Imports Microsoft.VisualBasic
Imports System.Text
Imports System.Collections.Generic
Public Class Main
Public Shared Function DoArithmaticFunctionFromStringInput(ByVal MathematicalString As String) As Double
    Dim numberList As New List(Of Number)
    Dim operationsList As New List(Of IOperatable)
    Dim currentNumber As New Number
    Dim currentParentheticalStatement As New Parenthetical
    Dim isInParentheticalMode As Boolean = False
    Dim allCharactersInString() As Char = MathematicalString.ToCharArray
    For Each mathChar In allCharactersInString
        If mathChar = Number.ZERO_STRING_REPRESENTATION Then
            currentNumber.UpdateNumber(mathChar)
        ElseIf mathChar = Number.ONE_STRING_REPRESENTATION Then
            currentNumber.UpdateNumber(mathChar)
        ElseIf mathChar = Number.TWO_STRING_REPRESENTATION Then
            currentNumber.UpdateNumber(mathChar)
        ElseIf mathChar = Number.THREE_STRING_REPRESENTATION Then
            currentNumber.UpdateNumber(mathChar)
        ElseIf mathChar = Number.FOUR_STRING_REPRESENTATION Then
            currentNumber.UpdateNumber(mathChar)
        ElseIf mathChar = Number.FIVE_STRING_REPRESENTATION Then
            currentNumber.UpdateNumber(mathChar)
        ElseIf mathChar = Number.SIX_STRING_REPRESENTATION Then
            currentNumber.UpdateNumber(mathChar)
        ElseIf mathChar = Number.SEVEN_STRING_REPRESENTATION Then
            currentNumber.UpdateNumber(mathChar)
        ElseIf mathChar = Number.EIGHT_STRING_REPRESENTATION Then
            currentNumber.UpdateNumber(mathChar)
        ElseIf mathChar = Number.NINE_STRING_REPRESENTATION Then
            currentNumber.UpdateNumber(mathChar)
        ElseIf mathChar = Number.DECIMAL_POINT_STRING_REPRESENTATION Then
            currentNumber.UpdateNumber(mathChar)
        ElseIf mathChar = Addition.ADDITION_STRING_REPRESENTATION Then
            Dim addition As New Addition

            If Not isInParentheticalMode Then
                operationsList.Add(addition)
                numberList.Add(currentNumber)
            Else
                currentParentheticalStatement.AllNumbers.Add(currentNumber)
                currentParentheticalStatement.AllOperators.Add(addition)
            End If

            currentNumber = New Number
        ElseIf mathChar = Number.NEGATIVE_NUMBER_STRING_REPRESENTATION Then
            If currentNumber.StringOfNumbers.Length > 0 Then
                currentNumber.UpdateNumber(mathChar)

                Dim subtraction As New Addition
                If Not isInParentheticalMode Then
                    operationsList.Add(subtraction)
                    numberList.Add(currentNumber)
                Else
                    currentParentheticalStatement.AllNumbers.Add(currentNumber)
                    currentParentheticalStatement.AllOperators.Add(subtraction)
                End If

                currentNumber = New Number
            Else
                currentNumber.UpdateNumber(mathChar)
            End If
        ElseIf mathChar = Multiplication.MULTIPLICATION_STRING_REPRESENTATION Then
            Dim multiplication As New Multiplication

            If Not isInParentheticalMode Then
                operationsList.Add(multiplication)
                numberList.Add(currentNumber)
            Else
                currentParentheticalStatement.AllNumbers.Add(currentNumber)
                currentParentheticalStatement.AllOperators.Add(multiplication)
            End If
            currentNumber = New Number
        ElseIf mathChar = Division.DIVISION_STRING_REPRESENTATION Then
            Dim division As New Division

            If Not isInParentheticalMode Then
                operationsList.Add(division)
                numberList.Add(currentNumber)
            Else
                currentParentheticalStatement.AllNumbers.Add(currentNumber)
                currentParentheticalStatement.AllOperators.Add(division)
            End If
            currentNumber = New Number
        ElseIf mathChar = Parenthetical.LEFT_PARENTHESIS_STRING_REPRESENTATION Then
            isInParentheticalMode = True
        ElseIf mathChar = Parenthetical.RIGHT_PARENTHESIS_STRING_REPRESENTATION Then
            currentNumber = currentParentheticalStatement.EvaluateParentheticalStatement
            numberList.Add(currentNumber)
            isInParentheticalMode = False
        End If
    Next

    Dim result As Double = 0
    Dim operationIndex As Integer = 0
    For Each numberOnWhichToPerformOperations As Number In numberList
        result = operationsList(operationIndex).PerformOperation(result, numberOnWhichToPerformOperations)
        operationIndex = operationIndex + 1
    Next

    Return result

End Function
Public Class Number
    Public Const DECIMAL_POINT_STRING_REPRESENTATION As Char = "."
    Public Const NEGATIVE_NUMBER_STRING_REPRESENTATION As Char = "-"
    Public Const ZERO_STRING_REPRESENTATION As Char = "0"
    Public Const ONE_STRING_REPRESENTATION As Char = "1"
    Public Const TWO_STRING_REPRESENTATION As Char = "2"
    Public Const THREE_STRING_REPRESENTATION As Char = "3"
    Public Const FOUR_STRING_REPRESENTATION As Char = "4"
    Public Const FIVE_STRING_REPRESENTATION As Char = "5"
    Public Const SIX_STRING_REPRESENTATION As Char = "6"
    Public Const SEVEN_STRING_REPRESENTATION As Char = "7"
    Public Const EIGHT_STRING_REPRESENTATION As Char = "8"
    Public Const NINE_STRING_REPRESENTATION As Char = "9"

    Private _isNegative As Boolean
    Public ReadOnly Property IsNegative() As Boolean
        Get
            Return _isNegative
        End Get
    End Property
    Public ReadOnly Property ActualNumber() As Double
        Get
            Dim result As String = ""
            If HasDecimal Then
                If DecimalIndex = StringOfNumbers.Length - 1 Then
                    result = StringOfNumbers.ToString
                Else
                    result = StringOfNumbers.Insert(DecimalIndex, DECIMAL_POINT_STRING_REPRESENTATION).ToString
                End If
            Else
                result = StringOfNumbers.ToString
            End If
            If IsNegative Then
                result = NEGATIVE_NUMBER_STRING_REPRESENTATION & result
            End If
            Return CType(result, Double)
        End Get
    End Property
    Private _hasDecimal As Boolean
    Public ReadOnly Property HasDecimal() As Boolean
        Get
            Return _hasDecimal
        End Get
    End Property
    Private _decimalIndex As Integer
    Public ReadOnly Property DecimalIndex() As Integer
        Get
            Return _decimalIndex
        End Get
    End Property
    Private _stringOfNumbers As New StringBuilder
    Public ReadOnly Property StringOfNumbers() As StringBuilder
        Get
            Return _stringOfNumbers
        End Get
    End Property
    Public Sub UpdateNumber(ByVal theDigitToAppend As Char)
        If IsNumeric(theDigitToAppend) Then
            Me._stringOfNumbers.Append(theDigitToAppend)
        ElseIf theDigitToAppend = DECIMAL_POINT_STRING_REPRESENTATION Then
            Me._hasDecimal = True
            Me._decimalIndex = Me._stringOfNumbers.Length
        ElseIf theDigitToAppend = NEGATIVE_NUMBER_STRING_REPRESENTATION Then
            Me._isNegative = Not Me._isNegative
        End If
    End Sub
    Public Shared Function ConvertDoubleToNumber(ByVal numberThatIsADouble As Double) As Number
        Dim numberResult As New Number
        For Each character As Char In numberThatIsADouble.ToString.ToCharArray
            numberResult.UpdateNumber(character)
        Next
        Return numberResult
    End Function
End Class
Public MustInherit Class Operation
    Protected _firstnumber As New Number
    Protected _secondnumber As New Number
    Public Property FirstNumber() As Number
        Get
            Return _firstnumber
        End Get
        Set(ByVal value As Number)
            _firstnumber = value
        End Set
    End Property
    Public Property SecondNumber() As Number
        Get
            Return _secondnumber
        End Get
        Set(ByVal value As Number)
            _secondnumber = value
        End Set
    End Property
End Class
Public Interface IOperatable
    Function PerformOperation(ByVal number1 As Double, ByVal number2 As Number) As Double
End Interface
Public Class Addition
    Inherits Operation
    Implements IOperatable
    Public Const ADDITION_STRING_REPRESENTATION As String = "+"
    Public Sub New()

    End Sub
    Public Function PerformOperation(ByVal number1 As Double, ByVal number2 As Number) As Double Implements IOperatable.PerformOperation
        Dim result As Double = 0
        result = number1 + number2.ActualNumber
        Return result
    End Function
End Class
Public Class Multiplication
    Inherits Operation
    Implements IOperatable
    Public Const MULTIPLICATION_STRING_REPRESENTATION As String = "*"
    Public Sub New()

    End Sub
    Public Function PerformOperation(ByVal number1 As Double, ByVal number2 As Number) As Double Implements IOperatable.PerformOperation
        Dim result As Double = 0
        result = number1 * number2.ActualNumber
        Return result
    End Function
End Class
Public Class Division
    Inherits Operation
    Implements IOperatable
    Public Const DIVISION_STRING_REPRESENTATION As String = "/"
    Public Const DIVIDE_BY_ZERO_ERROR_MESSAGE As String = "I took a lot of time to write this program. Please don't be a child and try to defile it by dividing by zero. Nobody thinks you are funny."
    Public Sub New()

    End Sub
    Public Function PerformOperation(ByVal number1 As Double, ByVal number2 As Number) As Double Implements IOperatable.PerformOperation
        If Not number2.ActualNumber = 0 Then
            Dim result As Double = 0
            result = number1 / number2.ActualNumber
            Return result
        Else
            Dim divideByZeroException As New Exception(DIVIDE_BY_ZERO_ERROR_MESSAGE)
            Throw divideByZeroException
        End If
    End Function
End Class
Public Class Parenthetical
    Public Const LEFT_PARENTHESIS_STRING_REPRESENTATION As String = "("
    Public Const RIGHT_PARENTHESIS_STRING_REPRESENTATION As String = ")"
    Private _allNumbers As New List(Of Number)
    Public Property AllNumbers() As List(Of Number)
        Get
            Return _allNumbers
        End Get
        Set(ByVal value As List(Of Number))
            _allNumbers = value
        End Set
    End Property
    Private _allOperators As New List(Of IOperatable)
    Public Property AllOperators() As List(Of IOperatable)
        Get
            Return _allOperators
        End Get
        Set(ByVal value As List(Of IOperatable))
            _allOperators = value
        End Set
    End Property
    Public Sub New()

    End Sub
    Public Function EvaluateParentheticalStatement() As Number
        Dim result As Double = 0
        Dim operationIndex As Integer = 0
        For Each numberOnWhichToPerformOperations As Number In AllNumbers
            result = AllOperators(operationIndex).PerformOperation(result, numberOnWhichToPerformOperations)
            operationIndex = operationIndex + 1
        Next

        Dim numberToReturn As New Number
        numberToReturn = Number.ConvertDoubleToNumber(result)
        Return numberToReturn
    End Function
End Class
End Class
Run Code Online (Sandbox Code Playgroud)

  • @ikke - 它应该尽可能少的角色?亲爱的...有人似乎错过了这一点 (11认同)
  • ZERO_STRING_REPRESENTATION看起来像属于thedailywtf的东西 (3认同)
  • 如果不是很晚,我也可能会打到10k个字符:) (2认同)

Dav*_*ave 23

蟒蛇

字符数:237

完全混淆的功能:

from operator import*
def e(s,l=[]):
 if s:l+=list(s.replace(' ','')+')')
 a=0;o=add;d=dict(zip(')*+-/',(0,mul,o,sub,div)));p=l.pop
 while o:
  c=p(0)
  if c=='(':c=e(0)
  while l[0]not in d:c+=p(0)
  a=o(a,float(c));o=d[p(0)]
 return a
Run Code Online (Sandbox Code Playgroud)

清除/半混淆功能:

import operator

def calc(source, stack=[]):
    if source:
        stack += list(source.replace(' ', '') + ')')

    answer = 0

    ops = {
        ')': 0,
        '*': operator.mul,
        '+': operator.add,
        '-': operator.sub,
        '/': operator.div,
    }

    op = operator.add
    while op:
        cur = stack.pop(0)

        if cur == '(':
            cur = calc(0)

        while stack[0] not in ops:
            cur += stack.pop(0)

        answer = op(answer, float(cur))
        op = ops[stack.pop(0)]

    return answer
Run Code Online (Sandbox Code Playgroud)


dmc*_*kee 20

Fortran 77(gfortran方言,现在支持g77)

字符数: 2059

混淆版本:

      function e(c)
      character*99 c
      character b
      real f(24)                
      integer i(24)             
      nf=0                      
      ni=0                      
 20   nf=kf(0.0,nf,f)
      ni=ki(43,ni,i)         
 30   if (isp(c).eq.1) goto 20
      h=fr(c)
 31   g=fp(nf,f)
      j=ip(ni,i)
      select case(j)
      case (40) 
         goto 20
      case (42)                 
         d=g*h
      case (43)                 
         d=g+h
      case (45)                 
         d=g-h
      case (47)                 
         d=g/h
      end select
 50   nf=kf(d,nf,f)
 60   j=nop(c)
      goto (20, 70, 75, 75, 60, 75, 60, 75) (j-39)
 65   e=fp(nf,f)
      return
 70   h=fp(nf,f)              
      goto 31
 75   ni=ki(j,ni,i)
      goto 30
      end
      function kf(v,n,f)
      real f(24)
      kf=n+1
      f(n+1)=v
      return
      end
      function ki(j,n,i)
      integer i(24)
      ki=n+1
      i(n+1)=j
      return
      end
      function fp(n,f)
      real f(24)
      fp=f(n)
      n=n-1
      return
      end
      function ip(n,i)
      integer i(24)
      ip=i(n)
      n=n-1
      return
      end
      function nop(s)
      character*99 s
      l=1
      do while(s(l:l).eq." ".and.l.lt.99)
         l=l+1
      enddo
      nop=ichar(s(l:l))
      s(l:l)=" "
      return
      end
      function isp(s)
      character*99 s
      isp=0
      l=1
      do while(s(l:l).eq." ".and.l.lt.99)
         l=l+1
      enddo
      isp=41-ichar(s(l:l))
      if (isp.eq.1) s(l:l)=" "
      return
      end
      function fr(s)
      character*99 s
      m=1                      
      n=1                      
      i=1
      do while(i.le.99)
         j=ichar(s(i:i))
         if (j.eq.32) goto 90   
         if (j.ge.48.and.j.lt.58) goto 89
         if (j.eq.43.or.j.eq.45) goto (89,80) m
         if (j.eq.46) goto (83,80) n
 80      exit
 83      n=2
 89      m=2
 90      i=i+1
      enddo
      read(s(1:i-1),*) fr
      do 91 j=1,i-1
         s(j:j)=" "
 91   continue
      return 
      end
Run Code Online (Sandbox Code Playgroud)

清除版本:(3340个字符与脚手架)

      program infixeval
      character*99 c
      do while (.true.)
         do 10 i=1,99
            c(i:i)=" "
 10      continue
         read(*,"(A99)") c
         f=e(c)
         write(*,*)f
      enddo
      end

      function e(c)
      character*99 c
      character b
      real f(24)                ! value stack
      integer i(24)             ! operator stack
      nf=0                      ! number of items on the value stack
      ni=0                      ! number of items on the operator stack
 20   nf=pushf(0.0,nf,f)
      ni=pushi(43,ni,i)         ! ichar(+) = 43
D     write (*,*) "'",c,"'"
 30   if (isp(c).eq.1) goto 20
      h=fr(c)
D     write (*,*) "'",c,"'"
 31   g=fpop(nf,f)
      j=ipop(ni,i)
D     write(*,*) "Opperate ",g," ",char(j)," ",h
      select case(j)
      case (40) 
         goto 20
      case (42)                 ! "*" 
         d=g*h
      case (43)                 ! "+"
         d=g+h
      case (45)                 ! "-"
         d=g-h
      case (47)                 ! "*"
         d=g/h
      end select
 50   nf=pushf(d,nf,f)
 60   j=nop(c)
D     write(*,*) "Got op: ", char(j)
      goto (20, 70, 75, 75, 60, 75, 60, 75) (j-39)
 65   e=fpop(nf,f)
      return
 70   h=fpop(nf,f)              ! Encountered a "("
      goto 31
 75   ni=pushi(j,ni,i)
      goto 30
      end

c     push onto a real stack
c     OB as kf
      function pushf(v,n,f)
      real f(24)
      pushf=n+1
      f(n+1)=v
D     write(*,*) "Push ", v
      return
      end

c     push onto a integer stack
c     OB as ki
      function pushi(j,n,i)
      integer i(24)
      pushi=n+1
      i(n+1)=j
D     write(*,*) "Push ", char(j)
      return
      end

c     pop from real stack
c     OB as fp
      function fpop(n,f)
      real f(24)
      fpop=f(n)
      n=n-1
D      write (*,*) "Pop ", fpop
      return
      end

c     pop from integer stack
c     OB as ip
      function ipop(n,i)
      integer i(24)
      ipop=i(n)
      n=n-1
D      write (*,*) "Pop ", char(ipop)
      return
      end

c     Next OPerator: returns the next nonws character, and removes it
c     from the string
      function nop(s)
      character*99 s
      l=1
      do while(s(l:l).eq." ".and.l.lt.99)
         l=l+1
      enddo
      nop=ichar(s(l:l))
      s(l:l)=" "
      return
      end

c     IS an open Paren: return 1 if the next non-ws character is "("
c     (also overwrite it with a space. Otherwise return not 1
      function isp(s)
      character*99 s
      isp=0
      l=1
      do while(s(l:l).eq." ".and.l.lt.99)
         l=l+1
      enddo
      isp=41-ichar(s(l:l))
      if (isp.eq.1) s(l:l)=" "
      return
      end

c     Float Read: return the next real number in the string and removes the
c     character
      function fr(s)
      character*99 s
      m=1                      ! No sign (Minus or plus) so far
      n=1                      ! No decimal so far
      i=1
      do while(i.le.99)
         j=ichar(s(i:i))
         if (j.eq.32) goto 90   ! skip spaces
         if (j.ge.48.and.j.lt.58) goto 89
         if (j.eq.43.or.j.eq.45) goto (89,80) m
         if (j.eq.46) goto (83,80) n
c     not part of a number
 80      exit
 83      n=2
 89      m=2
 90      i=i+1
      enddo
      read(s(1:i-1),*) fr
      do 91 j=1,i-1
         s(j:j)=" "
 91   continue
      return 
      end
Run Code Online (Sandbox Code Playgroud)

注意这个编辑过的版本比我的第一次尝试更加邪恶.相同的算法,但现在内联与gotos 的可怕纠结.我已经放弃了合作程序,但现在使用了几种计算分支.已删除所有错误检查和报告,但此版本将从输入中的某些类别的意外字符中静默恢复.这个版本也编译与g77.

主要限制仍然是fortran的严格格式化,长且无处不在的关键字和简单的原语.

  • 天哪,伙计!你今天一定很无聊.;) (14认同)
  • 呵呵,我不认为我曾经期待过Fortran解决方案!我想我们可以得出结论,这种语言不是特别适合编码高尔夫?无论如何都要投票支持纯粹的努力和使用过时的语言.:) (2认同)

Fer*_*cio 17

C99

字符数:239(但参见下面的209)

压缩功能:

#define S while(*e==32)++e
#define F float
F strtof();char*e;F v();F g(){S;return*e++-40?strtof(e-1,&e):v();}F v(){F b,a=g();for(;;){S;F o=*e++;if(!o|o==41)return a;b=g();a=o==43?a+b:o==45?a-b:o==42?a*b:a/b;}}F f(char*x){e=x;return v();}
Run Code Online (Sandbox Code Playgroud)

解压缩功能:

float strtof();

char* e;
float v();

float g() {
    while (*e == ' ') ++e;
    return *e++ != '(' ? strtof(e-1, &e) : v();
}

float v() {
    float b, a = g();
    for (;;) {
        while (*e == ' ') ++e;
        float op = *e++;
        if (op == 0 || op == ')') return a;
        b = g();
        a = op == '+' ? a + b : op == '-' ? a - b : op == '*' ? a * b : a / b;
    }
}

float eval(char* x) {
    e = x;
    return v();
}
Run Code Online (Sandbox Code Playgroud)

功能不是可重入的.

来自Chris Lutz的编辑:我讨厌践踏另一个人的代码,但这是一个209字符的版本:

#define S for(;*e==32;e++)
#define X (*e++-40?strtof(e-1,&e):v())
float strtof();char*e;float v(){float o,a=X;for(;;){S;o=*e++;if(!o|o==41)return a;S;a=o-43?o-45?o-42?a/X:a*X:a-X:a+X;}}
#define f(x) (e=x,v())
Run Code Online (Sandbox Code Playgroud)

可读(嗯,不是很可读,但解压缩):

float strtof();
char *e;
float v() {
    float o, a = *e++ != '(' ? strtof(e - 1, &e) : v();
    for(;;) {
        for(; *e == ' '; e++);
        o = *e++;
        if(o == 0 || o==')') return a;
        for(; *e == ' '; e++);
        // I have no idea how to properly indent nested conditionals
        // and this is far too long to fit on one line.
        a = o != '+' ?
          o != '-' ?
            o != '*' ?
              a / (*e++ != '(' ? strtof(e - 1, &e) : v()) :
              a * (*e++ != '(' ? strtof(e - 1, &e) : v()) :
            a - (*e++ != '(' ? strtof(e - 1, &e) : v()) :
          a + (*e++ != '(' ? strtof(e - 1, &e) : v());
      }
}
#define f(x) (e = x, v())
Run Code Online (Sandbox Code Playgroud)

是的,f()是一个宏,而不是一个功能,但它的工作原理.可读版本有一些逻辑被重写但没有重新排序(比如o != '+'代替o - '+'),但是只是另一个的缩进(和预处理)版本.我一直试图将if(!o|o==41)return a;部分简化为for()循环,但它永远不会缩短.我仍然相信它可以做到,但我已经完成了打高尔夫球.如果我再处理这个问题,它将使用不能命名的语言.


小智 13

Common Lisp

(SBCL)
字符数:251

(defun g(e)(if(numberp e)e(let((m (g (pop e)))(o(loop for x in e by #'cddr collect x))(n(loop for x in (cdr e)by #'cddr collect (g x))))(mapcar(lambda(x y)(setf m(apply x(list m y))))o n)m)))(defun w(e)(g(read-from-string(concatenate'string"("e")"))))
Run Code Online (Sandbox Code Playgroud)

正确版本(387个字符):

(defun wrapper (exp) (golf-eval (read-from-string (concatenate 'string "(" exp ")"))))

(defun golf-eval (exp)
 (if (numberp exp)
     exp
   (let ((mem (golf-eval (pop exp)))
     (op-list (loop for x in exp by #'cddr collect x))
     (num-list (loop for x in (cdr exp) by #'cddr collect (golf-eval x))))
    (mapcar (lambda (x y) (setf mem (apply x (list mem y)))) op-list num-list)
    mem)))
Run Code Online (Sandbox Code Playgroud)

输入是表单w(),它接受一个字符串参数.它使用nums /操作数和运算符在NONON模式中的技巧......并递归地计算所有操作数,因此嵌套非常便宜.;)


Mat*_*ley 11

JavaScript(不兼容IE)

字符数:268/260

完全混淆的功能:

function e(x){x=x.replace(/ /g,'')+')'
function P(n){return x[0]=='('?(x=x.substr(1),E()):(n=/^[-+]?[\d.]+/(x)[0],x=x.substr(n.length),+n)}function E(a,o,b){a=P()
for(;;){o=x[0]
x=x.substr(1)
if(o==')')return a
b=P()
a=o=='+'?a+b:o=='-'?a-b:o=='*'?a*b:a/b}}return E()}
Run Code Online (Sandbox Code Playgroud)

或者,在JavaScript 1.8(Firefox 3+)中,您可以使用表达式闭包来保存几个字符:

e=function(x,P,E)(x=x.replace(/ /g,'')+')',P=function(n)(x[0]=='('?(x=x.substr(1),E()):(n=/^[-+]?[\d.]+/(x)[0],x=x.substr(n.length),+n)),E=function(a,o,b){a=P()
for(;;){o=x[0]
x=x.substr(1)
if(o==')')return a
b=P()
a=o=='+'?a+b:o=='-'?a-b:o=='*'?a*b:a/b}},E())
Run Code Online (Sandbox Code Playgroud)

清除/半混淆功能:

function evaluate(x) {
    x = x.replace(/ /g, "") + ")";
    function primary() {
        if (x[0] == '(') {
            x = x.substr(1);
            return expression();
        }

        var n = /^[-+]?\d*\.?\d*/.exec(x)[0];
        x = x.substr(n.length);
        return +n;
    }

    function expression() {
        var a = primary();
        for (;;) {
            var operator = x[0];
            x = x.substr(1);

            if (operator == ')') {
                return a;
            }

            var b = primary();
            a = (operator == '+') ? a + b :
                (operator == '-') ? a - b :
                (operator == '*') ? a * b :
                                    a / b;
        }
    }

    return expression();
}
Run Code Online (Sandbox Code Playgroud)

这两个版本都不适用于IE,因为它们在字符串上使用数组样式的下标.如果更换两次出现的x[0]x.charAt(0),第一个应该在任何地方工作.

通过将变量转换为函数参数并用条件运算符替换另一个if语句,我从第一个版本开始删除了一些字符.


sou*_*rge 8

PHP

字符数:284

模糊:

function f($m){return c($m[1]);}function g($n,$m){$o=$m[0];$m[0]=' ';return$o=='+'?$n+$m:($o=='-'?$n-$m:($o=='*'?$n*$m:$n/$m));}function c($s){while($s!=($t=preg_replace_callback('/\(([^()]*)\)/',f,$s)))$s=$t;preg_match_all('![-+/*].*?[\d.]+!',"+$s",$m);return array_reduce($m[0],g);}
Run Code Online (Sandbox Code Playgroud)

可读:

function callback1($m) {return c($m[1]);}
function callback2($n,$m) {
    $o=$m[0];
    $m[0]=' ';
    return $o=='+' ? $n+$m : ($o=='-' ? $n-$m : ($o=='*' ? $n*$m : $n/$m));
}
function c($s){ 
    while ($s != ($t = preg_replace_callback('/\(([^()]*)\)/','callback1',$s))) $s=$t;
    preg_match_all('![-+/*].*?[\d.]+!', "+$s", $m);
    return array_reduce($m[0], 'callback2');
}


$str = '  2.45/8.5  *  -9.27   +    (   5   *  0.0023  ) ';
var_dump(c($str));
# float(-2.66044117647)
Run Code Online (Sandbox Code Playgroud)

应该使用任何有效的输入(包括负数和任意空格)


Jef*_*ser 8

C#与正则表达式爱

字符数: 384

完全混淆:

float E(string i){i=i.Replace(" ","");Regex b=new Regex(@"\((?>[^()]+|\((?<D>)|\)(?<-D>))*(?(D)(?!))\)");i=b.Replace(i,m=>Eval(m.Value.Substring(1,m.Length-2)).ToString());float r=0;foreach(Match m in Regex.Matches(i,@"(?<=^|\D)-?[\d.]+")){float f=float.Parse(m.Value);if(m.Index==0)r=f;else{char o=i[m.Index-1];if(o=='+')r+=f;if(o=='-')r-=f;if(o=='*')r*=f;if(o=='/')r/=f;}}return r;}
Run Code Online (Sandbox Code Playgroud)

不能混淆:

private static float Eval(string input)
{
    input = input.Replace(" ", "");
    Regex balancedMatcher = new Regex(@"\(
                                            (?>
                                                [^()]+
                                            |
                                                \( (?<Depth>)
                                            |
                                                \) (?<-Depth>)
                                            )*
                                            (?(Depth)(?!))
                                        \)", RegexOptions.IgnorePatternWhitespace);
    input = balancedMatcher.Replace(input, m => Eval(m.Value.Substring(1, m.Length - 2)).ToString());

    float result = 0;

    foreach (Match m in Regex.Matches(input, @"(?<=^|\D)-?[\d.]+"))
    {
        float floatVal = float.Parse(m.Value);
        if (m.Index == 0)
        {
            result = floatVal;
        }
        else
        {
            char op = input[m.Index - 1];
            if (op == '+') result += floatVal;
            if (op == '-') result -= floatVal;
            if (op == '*') result *= floatVal;
            if (op == '/') result /= floatVal;
        }
    }

    return result;
}
Run Code Online (Sandbox Code Playgroud)

利用.NET的Regex 平衡组功能.


小智 8

SQL(SQL Server 2008)

字符数:4202

完全混淆的功能:

WITH Input(id,str)AS(SELECT 1,'1 + 3 / -8'UNION ALL SELECT 2,'2*3*4*5+99'UNION ALL SELECT 3,'4 * (9 - 4)/ (2 * 6 - 2)+ 8'UNION ALL SELECT 4,'1 + ((123 * 3 - 69)/ 100)'UNION ALL SELECT 5,'2.45/8.5*9.27+(5*0.0023)'),Separators(i,ch,str_src,priority)AS(SELECT 1,'-',1,1UNION ALL SELECT 2,'+',1,1UNION ALL SELECT 3,'*',1,1UNION ALL SELECT 4,'/',1,1UNION ALL SELECT 5,'(',0,0UNION ALL SELECT 6,')',0,0),SeparatorsStrSrc(str,i)AS(SELECT CAST('['AS varchar(max)),0UNION ALL SELECT str+ch,SSS.i+1FROM SeparatorsStrSrc SSS INNER JOIN Separators S ON SSS.i=S.i-1WHERE str_src<>0),SeparatorsStr(str)AS(SELECT str+']'FROM SeparatorsStrSrc WHERE i=(SELECT COUNT(*)FROM Separators WHERE str_src<>0)),ExprElementsSrc(id,i,tmp,ele,pre_ch,input_str)AS(SELECT id,1,CAST(LEFT(str,1)AS varchar(max)),CAST(''AS varchar(max)),CAST(' 'AS char(1)),SUBSTRING(str,2,LEN(str))FROM Input UNION ALL SELECT id,CASE ele WHEN''THEN i ELSE i+1 END,CAST(CASE WHEN LEFT(input_str,1)=' 'THEN''WHEN tmp='-'THEN CASE WHEN pre_ch LIKE(SELECT str FROM SeparatorsStr)THEN tmp+LEFT(input_str,1)ELSE LEFT(input_str,1)END WHEN LEFT(input_str,1)IN(SELECT ch FROM Separators)OR tmp IN(SELECT ch FROM Separators)THEN LEFT(input_str,1)ELSE tmp+LEFT(input_str,1)END AS varchar(max)),CAST(CASE WHEN LEFT(input_str,1)=' 'THEN tmp WHEN LEFT(input_str,1)='-'THEN CASE WHEN tmp IN(SELECT ch FROM Separators)THEN tmp ELSE''END WHEN LEFT(input_str,1)IN(SELECT ch FROM Separators)OR tmp IN(SELECT ch FROM Separators)THEN CASE WHEN tmp='-'AND pre_ch LIKE(SELECT str FROM SeparatorsStr)THEN''ELSE tmp END ELSE''END AS varchar(max)),CAST(LEFT(ele,1)AS char(1)),SUBSTRING(input_str,2,LEN(input_str))FROM ExprElementsSrc WHERE input_str<>''OR tmp<>''),ExprElements(id,i,ele)AS(SELECT id,i,ele FROM ExprElementsSrc WHERE ele<>''),Scanner(id,i,val)AS(SELECT id,i,CAST(ele AS varchar(max))FROM ExprElements WHERE ele<>''UNION ALL SELECT id,MAX(i)+1,NULL FROM ExprElements GROUP BY id),Operator(op,priority)AS(SELECT ch,priority FROM Separators WHERE priority<>0),Calc(id,c,i,pop_count,s0,s1,s2,stack,status)AS(SELECT Scanner.id,1,1,0,CAST(scanner.val AS varchar(max)),CAST(NULL AS varchar(max)),CAST(NULL AS varchar(max)),CAST(''AS varchar(max)),CAST('init'AS varchar(max))FROM Scanner WHERE Scanner.i=1UNION ALL SELECT Calc.id,Calc.c+1,Calc.i,3,NULL,NULL,NULL,CASE Calc.s1 WHEN'+'THEN CAST(CAST(Calc.s2 AS real)+CAST(Calc.s0 AS real)AS varchar(max))WHEN'-'THEN CAST(CAST(Calc.s2 AS real)-CAST(Calc.s0 AS real)AS varchar(max))WHEN'*'THEN CAST(CAST(Calc.s2 AS real)*CAST(Calc.s0 AS real)AS varchar(max))WHEN'/'THEN CAST(CAST(Calc.s2 AS real)/CAST(Calc.s0 AS real)AS varchar(max))ELSE NULL END+' '+stack,CAST('calc '+Calc.s1 AS varchar(max))FROM Calc INNER JOIN Scanner NextVal ON Calc.id=NextVal.id AND Calc.i+1=NextVal.i WHERE Calc.pop_count=0AND ISNUMERIC(Calc.s2)=1AND Calc.s1 IN(SELECT op FROM Operator)AND ISNUMERIC(Calc.s0)=1AND(SELECT priority FROM Operator WHERE op=Calc.s1)>=COALESCE((SELECT priority FROM Operator WHERE op=NextVal.val),0)UNION ALL SELECT Calc.id,Calc.c+1,Calc.i,3,NULL,NULL,NULL,s1+' '+stack,CAST('paren'AS varchar(max))FROM Calc WHERE pop_count=0AND s2='('AND ISNUMERIC(s1)=1AND s0=')'UNION ALL SELECT Calc.id,Calc.c+1,Calc.i,Calc.pop_count-1,s1,s2,CASE WHEN LEN(stack)>0THEN SUBSTRING(stack,1,CHARINDEX(' ',stack)-1)ELSE NULL END,CASE WHEN LEN(stack)>0THEN SUBSTRING(stack,CHARINDEX(' ',stack)+1,LEN(stack))ELSE''END,CAST('pop'AS varchar(max))FROM Calc WHERE Calc.pop_count>0UNION ALL SELECT Calc.id,Calc.c+1,Calc.i+1,Calc.pop_count,CAST(NextVal.val AS varchar(max)),s0,s1,coalesce(s2,'')+' '+stack,cast('read'as varchar(max))FROM Calc INNER JOIN Scanner NextVal ON Calc.id=NextVal.id AND Calc.i+1=NextVal.i WHERE NextVal.val IS NOT NULL AND Calc.pop_count=0AND((Calc.s0 IS NULL OR calc.s1 IS NULL OR calc.s2 IS NULL)OR NOT(ISNUMERIC(Calc.s2)=1AND Calc.s1 IN(SELECT op FROM Operator)AND ISNUMERIC(calc.s0)=1AND (SELECT priority FROM Operator WHERE op=Calc.s1)>=COALESCE((SELECT priority FROM Operator WHERE op=NextVal.val),0))AND NOT(s2='('AND ISNUMERIC(s1)=1AND s0=')')))SELECT Calc.id,Input.str,Calc.s0 AS result FROM Calc INNER JOIN Input ON Calc.id=Input.id WHERE Calc.c=(SELECT MAX(c)FROM Calc calc2 WHERE Calc.id=Calc2.id)ORDER BY id
Run Code Online (Sandbox Code Playgroud)

清除/半混淆功能:

WITH
  Input(id, str) AS (    
    SELECT 1, '1 + 3 / -8'
    UNION ALL SELECT 2, '2*3*4*5+99'
    UNION ALL SELECT 3, '4 * (9 - 4) / (2 * 6 - 2) + 8'
    UNION ALL SELECT 4, '1 + ((123 * 3 - 69) / 100)'
    UNION ALL SELECT 5, '2.45/8.5*9.27+(5*0.0023)'
  )
, Separators(i, ch, str_src, priority) AS (
    SELECT 1, '-', 1, 1
    UNION ALL SELECT 2, '+', 1, 1
    UNION ALL SELECT 3, '*', 1, 1
    UNION ALL SELECT 4, '/', 1, 1
    UNION ALL SELECT 5, '(', 0, 0
    UNION ALL SELECT 6, ')', 0, 0
  )
, SeparatorsStrSrc(str, i) AS (
    SELECT CAST('[' AS varchar(max)), 0
    UNION ALL
    SELECT
        str + ch
      , SSS.i + 1
    FROM
        SeparatorsStrSrc SSS
          INNER JOIN Separators S ON SSS.i = S.i - 1
    WHERE
        str_src <> 0
  )
, SeparatorsStr(str) AS (
    SELECT str + ']' FROM SeparatorsStrSrc
    WHERE i = (SELECT COUNT(*) FROM Separators WHERE str_src <> 0)
  )
, ExprElementsSrc(id, i, tmp, ele, pre_ch, input_str) AS (
    SELECT
        id
      , 1
      , CAST(LEFT(str, 1) AS varchar(max))
      , CAST('' AS varchar(max))
      , CAST(' ' AS char(1))
      , SUBSTRING(str, 2, LEN(str))
    FROM
        Input
    UNION ALL
    SELECT
        id
      , CASE ele
        WHEN '' THEN i
                ELSE i + 1
        END
      , CAST(
          CASE
          WHEN LEFT(input_str, 1) = ' '
            THEN ''
          WHEN tmp = '-'
            THEN CASE
                 WHEN pre_ch LIKE (SELECT str FROM SeparatorsStr)
                   THEN tmp + LEFT(input_str, 1)
                   ELSE LEFT(input_str, 1)
                 END
          WHEN LEFT(input_str, 1) IN (SELECT ch FROM Separators)
               OR
               tmp IN (SELECT ch FROM Separators)
            THEN LEFT(input_str, 1)
            ELSE tmp + LEFT(input_str, 1)
          END
        AS varchar(max))
      , CAST(
          CASE
          WHEN LEFT(input_str, 1) = ' '
            THEN tmp
          WHEN LEFT(input_str, 1) = '-'
            THEN CASE
                 WHEN tmp IN (SELECT ch FROM Separators)
                   THEN tmp
                   ELSE ''
                 END
          WHEN LEFT(input_str, 1) IN (SELECT ch FROM Separators)
               OR
               tmp IN (SELECT ch FROM Separators)
            THEN CASE
                 WHEN tmp = '-' AND pre_ch LIKE (SELECT str FROM SeparatorsStr)
                   THEN ''
                   ELSE tmp
                 END
            ELSE ''
          END
        AS varchar(max))
      , CAST(LEFT(ele, 1) AS char(1))
      , SUBSTRING(input_str, 2, LEN(input_str))
    FROM
        ExprElementsSrc
    WHERE
        input_str <> ''
        OR
        tmp <> ''
  )
, ExprElements(id, i, ele) AS (
    SELECT
        id
      , i
      , ele
    FROM
        ExprElementsSrc
    WHERE
        ele <> ''
  )
, Scanner(id, i, val) AS (
    SELECT
        id
      , i
      , CAST(ele AS varchar(max))
    FROM
        ExprElements
    WHERE
        ele <> ''
    UNION ALL
    SELECT
        id
      , MAX(i) + 1
      , NULL
    FROM
        ExprElements
    GROUP BY
        id
  )
, Operator(op, priority) AS (
    SELECT
        ch
      , priority 
    FROM
        Separators
    WHERE
        priority <> 0
  )
, Calc(id, c, i, pop_count, s0, s1, s2, stack, status) AS (
    SELECT
        Scanner.id
      , 1
      , 1
      , 0
      , CAST(scanner.val AS varchar(max))
      , CAST(NULL AS varchar(max))
      , CAST(NULL AS varchar(max))
      , CAST('' AS varchar(max))
      , CAST('init' AS varchar(max))
    FROM
        Scanner
    WHERE
        Scanner.i = 1
    UNION ALL
    SELECT
        Calc.id
      , Calc.c + 1
      , Calc.i
      , 3
      , NULL
      , NULL
      , NULL
      , CASE Calc.s1
        WHEN '+' THEN CAST(CAST(Calc.s2 AS real) + CAST(Calc.s0 AS real) AS varchar(max))
        WHEN '-' THEN CAST(CAST(Calc.s2 AS real) - CAST(Calc.s0 AS real) AS varchar(max))
        WHEN '*' THEN CAST(CAST(Calc.s2 AS real) * CAST(Calc.s0 AS real) AS varchar(max))
        WHEN '/' THEN CAST(CAST(Calc.s2 AS real) / CAST(Calc.s0 AS real) AS varchar(max))
                 ELSE NULL
        END
          + ' '
          + stack
      , CAST('calc ' + Calc.s1 AS varchar(max))
    FROM
        Calc
          INNER JOIN Scanner NextVal ON Calc.id = NextVal.id
                                          AND Calc.i + 1 = NextVal.i
    WHERE
        Calc.pop_count = 0
          AND ISNUMERIC(Calc.s2) = 1
          AND Calc.s1 IN (SELECT op FROM Operator)
          AND ISNUMERIC(Calc.s0) = 1
          AND (SELECT priority FROM Operator WHERE op = Calc.s1)
            >= COALESCE((SELECT priority FROM Operator WHERE op = NextVal.val), 0)
    UNION ALL
    SELECT
        Calc.id
      , Calc.c + 1
      , Calc.i
      , 3
      , NULL
      , NULL
      , NULL
      , s1 + ' ' + stack
      , CAST('paren' AS varchar(max))
    FROM
        Calc
    WHERE
        pop_count = 0
          AND s2 = '('
          AND ISNUMERIC(s1) = 1
          AND s0 = ')'
    UNION ALL
    SELECT
        Calc.id
      , Calc.c + 1
      , Calc.i
      , Calc.pop_count - 1
      , s1
      , s2
      , CASE
        WHEN LEN(stack) > 0
          THEN SUBSTRING(stack, 1, CHARINDEX(' ', stack) - 1)
          ELSE NULL
        END
      , CASE
        WHEN LEN(stack) > 0
          THEN SUBSTRING(stack, CHARINDEX(' ', stack) + 1, LEN(stack))
          ELSE ''
        END
      , CAST('pop' AS varchar(max))
    FROM
        Calc
    WHERE
        Calc.pop_count > 0
    UNION ALL
    SELECT
        Calc.id
      , Calc.c + 1
      , Calc.i + 1
      , Calc.pop_count
      , CAST(NextVal.val AS varchar(max))
      , s0
      , s1
      , coalesce(s2, '') + ' ' + stack
      , cast('read' as varchar(max))
    FROM
        Calc
          INNER JOIN Scanner NextVal ON Calc.id = NextVal.id
                                          AND Calc.i + 1 = NextVal.i
    WHERE
        NextVal.val IS NOT NULL
          AND Calc.pop_count = 0
          AND (
            (Calc.s0 IS NULL or calc.s1 is null or calc.s2 is null)
            OR
            NOT(
              ISNUMERIC(Calc.s2) = 1
                AND Calc.s1 IN (SELECT op FROM Operator)
                AND ISNUMERIC(calc.s0) = 1
                AND (SELECT priority FROM Operator WHERE op = Calc.s1)
                  >= COALESCE((SELECT priority FROM Operator WHERE op = NextVal.val), 0)
            )
              AND NOT(s2 = '(' AND ISNUMERIC(s1) = 1 AND s0 = ')')
          )
  )
SELECT
    Calc.id
  , Input.str
  , Calc.s0 AS result
FROM
    Calc
      INNER JOIN Input ON Calc.id = Input.id
WHERE
    Calc.c = (SELECT MAX(c) FROM Calc calc2
              WHERE Calc.id = Calc2.id)
ORDER BY
    id
Run Code Online (Sandbox Code Playgroud)

它不是最短的.但我认为它对SQL非常灵活.添加新运算符很容易.改变运营商的优先级很容易.

  • @Noldorin,为什么不是代码高尔夫的精神? (2认同)

thr*_*thr 6

F#

字符数:327

OP正在寻找一个F#版本,就在这里.可以做得更好,因为我在这里滥用ref来保存角色.它处理大多数事情,如- (1.0),3 - -3甚至0 - .5等.

let g s=
 let c=ref[for x in System.Text.RegularExpressions.Regex.Matches(s,"[0-9.]+|[^\s]")->x.Value]
 let rec e v=if (!c).IsEmpty then v else 
  let h=(!c).Head
  c:=(!c).Tail
  match h with|"("->e(e 0.0)|")"->v|"+"->e(v+(e 0.0))|"-"->e(v-(e 0.0))|"/"->e(v/(e 0.0))|"*"->e(v*(e 0.0))|x->float x
 e(e 0.0)
Run Code Online (Sandbox Code Playgroud)


kru*_*ubo 6

Python(不导入任何东西)

字符数:222

我从戴夫的答案中偷走了许多技巧,但我还是设法削减了一些角色.

def e(s,l=0,n=0,f='+'):
 if s:l=[c for c in s+')'if' '!=c]
 while f!=')':
  p=l.pop;m=p(0)
  if m=='(':m=e(0,l)
  while l[0]not in'+-*/)':m+=p(0)
  m=float(m);n={'+':n+m,'-':n-m,'*':n*m,'/':n/(m or 1)}[f];f=p(0)
 return n
Run Code Online (Sandbox Code Playgroud)

评论版:

def evaluate(stringexpr, listexpr=0, n=0, f_operation='+'):
    # start out as taking 0 + the expression... (or could use 1 * ;)

    # We'll prefer to keep the expression as a list of characters,
    # so we can use .pop(0) to eat up the expression as we go.
    if stringexpr:
        listexpr = [c for c in stringexpr+')' if c!=' ']

    # use ')' as sentinel to return the answer
    while f_operation != ')':
        m_next = listexpr.pop(0)
        if m_next == '(':
            # lists are passed by reference, so this call will eat the (parexp)
            m_next = evaluate(None, listexpr)

        else:
            # rebuild any upcoming numeric chars into a string
            while listexpr[0] not in '+-*/)':
                m_next += listexpr.pop(0)

        # Update n as the current answer.  But never divide by 0.
        m = float(m_next)
        n = {'+':n+m, '-':n-m, '*':n*m, '/':n/(m or 1)}[f_operation]

        # prepare the next operation (known to be one of '+-*/)')
        f_operation = listexpr.pop(0)

    return n
Run Code Online (Sandbox Code Playgroud)


eph*_*ent 6

Ĵ

字符数:208

Jeff Moser的评论之后,我意识到我完全忘记了这种语言......我不是专家,但我的第一次尝试进展顺利.

e=:>@{:@f@;:
f=:''&(4 :0)
'y x'=.x g y
while.($y)*-.')'={.>{.y do.'y x'=.(x,>(-.'/'={.>{.y){('%';y))g}.y end.y;x
)
g=:4 :0
z=.>{.y
if.z='('do.'y z'=.f}.y else.if.z='-'do.z=.'_',>{.}.y end.end.(}.y);":".x,z
)
Run Code Online (Sandbox Code Playgroud)

这是一个有点恼人,不得不映射x/y-z成J的x%y_z.没有它,可能有50%的代码可能会消失.


Nol*_*rin 5

C#

字符数:403

所以这是我的解决方案......我还在等待有人在C#中发布一个可以击败它的人.(Marc Gravell很接近,经过一些修修补补后,可能会比我更好.)

完全混淆的功能:

float e(string x){float v=0;if(float.TryParse(x,out v))return v;x+=';';int t=0;
char o,s='?',p='+';float n=0;int l=0;for(int i=0;i<x.Length;i++){o=s;if(
x[i]!=' '){s=x[i];if(char.IsDigit(x[i])|s=='.'|(s=='-'&o!='1'))s='1';if(s==')')
l--;if(s!=o&l==0){if(o=='1'|o==')'){n=e(x.Substring(t,i-t));if(p=='+')v+=n;
if(p=='-')v-=n;if(p=='*')v*=n;if(p=='/')v/=n;p=x[i];}t=i;if(s=='(')t++;}
if(s=='(')l++;}}return v;}
Run Code Online (Sandbox Code Playgroud)

半混淆功能:

public static float Eval(string expr)
{
    float val = 0;
    if (float.TryParse(expr, out val))
        return val;
    expr += ';';
    int tokenStart = 0;
    char oldState, state = '?', op = '+';
    float num = 0;
    int level = 0;
    for (int i = 0; i < expr.Length; i++)
    {
        oldState = state;
        if (expr[i] != ' ')
        {
            state = expr[i];
            if (char.IsDigit(expr[i]) || state == '.' ||
                (state == '-' && oldState != '1'))
                state = '1';
            if (state == ')')
                level--;
            if (state != oldState && level == 0)
            {
                if (oldState == '1' || oldState == ')')
                {
                    num = Eval(expr.Substring(tokenStart, i - tokenStart));
                    if (op == '+') val += num;
                    if (op == '-') val -= num;
                    if (op == '*') val *= num;
                    if (op == '/') val /= num;
                    op = expr[i];
                }
                tokenStart = i;
                if (state == '(')
                    tokenStart++;
            }
            if (state == '(')
                level++;
        }
    }
    return val;
}
Run Code Online (Sandbox Code Playgroud)

没有什么比这更聪明了,看起来似乎很糟糕.然而,该功能具有可重入(即线程安全)的优点.

鉴于它是用C#编写的(我相信有效的1.0,2.0和3.0),我对字符的数量也相当满意.


Rob*_*t K 5

红宝石

字符数:170

混淆:

def s(x)
while x.sub!(/\(([^\(\)]*?)\)/){s($1)}
x.gsub!('--','')
end
while x.sub!(/(-?[\d.]+)[ ]*([+\-*\/])[ ]*(-?[\d.]+)/){$1.to_f.send($2,$3.to_f)}
end
x.strip.to_f
end
Run Code Online (Sandbox Code Playgroud)

读:

def s(x)
while x.sub!(/\(([^\(\)]*?)\)/){s($1)}
x.gsub!('--','')
end
while x.sub!(/(-?[\d.]+)[ ]*([+\-*\/])[ ]*(-?[\d.]+)/){$1.to_f.send($2,$3.to_f)}
end
x.strip.to_f
end

[
  ['1 + 3 / -8', -0.5],
  ['2*3*4*5+99', 219],
  ['4 * (9 - 4) / (2 * 6 - 2) + 8', 10],
  ['1 + ((123 * 3 - 69) / 100)', 4],
  ['2.45/8.5*9.27+(5*0.0023)',2.68344117647059],
  ['(3+7) - (5+2)', 3]
].each do |pair|
  a,b = s(String.new(pair[0])),pair[1]
  print pair[0].ljust(25), ' = ', b, ' (', a==b, ')'
  puts
end
Run Code Online (Sandbox Code Playgroud)

这个没有真正的混淆,我决定发布新的,因为它与我的第一个完全不同.我应该从一开始就看到这一点.该过程是一个非常简单的消除过程:找到并解析最高的一对括号(最嵌套的)到一个数字,直到找不到更多,然后将所有现有的数字和操作解析为结果.并且,在解析括号语句时,我将它删除所有双破折号(Float.to_f不知道如何处理它们).

因此,它支持正数和负数(+ 3,3,&-3),甚至仅通过处理顺序否定括号内的子表达式.唯一较短的实现是Perl(w/o eval).

编辑:我还在追逐Perl,但这是目前第二小的答案.我通过更改第二个正则表达式并将字符串的处理更改为破坏性(替换旧字符串)来缩小它.这消除了复制字符串的需要,我发现它只是一个新的字符串指针.并将函数重命名为s from resolve保存了几个字符.


sou*_*rge 5

这是另一个:

Shell脚本(使用sed + awk)

字符数:295

模糊:

e(){ a="$1";while echo "$a"|grep -q \(;do eval "`echo "$a"|sed 's/\(.*\)(\([^()]*\))\(.*\)/a="\1\`e \"\2\"\`\3"/'`";done; echo "$a"|sed 's/\([-+*/]\) *\(-\?\) */ \1 \2/g'|awk '{t=$1;for(i=2;i<NF;i+=2){j=$(i+1);if($i=="+") t+=j; else if($i=="-") t-=j; else if($i=="*") t*=j; else t/=j}print t}';}
Run Code Online (Sandbox Code Playgroud)

可读

e () {
    a="$1"
    # Recursively process bracket-expressions
    while echo "$a"|grep -q \(; do
        eval "`echo "$a"|
            sed 's/\(.*\)(\([^()]*\))\(.*\)/a="\1\`e \"\2\"\`\3"/'`"
    done
    # Compute expression without brackets
    echo "$a"|
        sed 's/\([-+*/]\) *\(-\?\) */ \1 \2/g'|
        awk '{
            t=$1;
            for(i=2;i<NF;i+=2){
                j=$(i+1);
                if($i=="+") t+=j;
                else if($i=="-") t-=j;
                else if($i=="*") t*=j;
                else t/=j
            }
            print t
        }'
}
Run Code Online (Sandbox Code Playgroud)

测试:

str='  2.45 / 8.5  *  9.27   +    (   5   *  0.0023  ) '
echo "$str"|bc -l
e "$str"
Run Code Online (Sandbox Code Playgroud)

结果:

2.68344117647058823526
2.68344
Run Code Online (Sandbox Code Playgroud)


gno*_*ice 5

MATLAB(v7.8.0)

字符数:239

混淆功能:

function [v,s]=m(s),r=1;while s,s=regexp(s,'( ?)(?(1)-?)[\.\d]+|\S','match');c=s{end};s=[s{1:end-1}];if any(c>47),v=str2num(c);elseif c>41,[l,s]=m(s);v=[l/v l*v l+v l-v];v=v(c=='/*+-');if r,break;end;r=1;elseif c<41,break;end;r=r&c~=41;end
Run Code Online (Sandbox Code Playgroud)

清除(呃)功能:

function [value,str] = math(str)
  returnNow = 1;
  while str,
    str = regexp(str,'( ?)(?(1)-?)[\.\d]+|\S','match');
    current = str{end};
    str = [str{1:end-1}];
    if any(current > 47),
      value = str2num(current);
    elseif current > 41,
      [leftValue,str] = math(str);
      value = [leftValue/value leftValue*value ...
               leftValue+value leftValue-value];
      value = value(current == '/*+-');
      if returnNow,
        break;
      end;
      returnNow = 1;
    elseif current < 41,
      break;
    end;
    returnNow = returnNow & (c ~= 41);
  end
Run Code Online (Sandbox Code Playgroud)

测试:

>> [math('1 + 3 / -8'); ...
math('2*3*4*5+99'); ...
math('4 * (9 - 4) / (2 * 6 - 2) + 8'); ...
math('1 + ((123 * 3 - 69) / 100)'); ...
math('2.45/8.5*9.27+(5*0.0023)')]

ans =

   -0.5000
  219.0000
   10.0000
    4.0000
    2.6834
Run Code Online (Sandbox Code Playgroud)

概要:正则表达式和递归的混合.几乎是迄今为止我能做到的最好的,没有作弊和使用EVAL.