Crie uma calculadora omnifix

16

Inspiração. Inverso.

Avalie uma expressão omnifixo fornecida.

Omnifix é como a notação de infixo da matemática normal, mas com cópias adicionais de cada símbolo em torno dos argumentos. Os símbolos externos substituem os parênteses e, portanto, não há necessidade de parênteses adicionais.

Você deve suportar adição, subtração, multiplicação, divisão e números reais positivos (números negativos podem ser escritos -0-n-) dentro de um intervalo razoável para o seu idioma.

Mais e menos devem ser +e -, mas você pode usar *ou ×por tempos e /ou ÷por divisão. Outros símbolos razoáveis ​​serão permitidos mediante solicitação.

Brownie aponta para explicação e recursos adicionais (como operações adicionais, números negativos, seqüências de caracteres etc.) Mesmo que sua resposta não possua esses recursos, fique à vontade para mostrar como poderia.

Forneça um link para testar sua solução, se possível.

Exemplos

Para maior clareza, as explicações abaixo usam alto menos ( ¯) para indicar números negativos. Você pode retornar números negativos usando qualquer formato razoável.

-5-2-3

+2+×3×2×+8 ( +2+×3×2×++2+6+8)

-14--3-1--12 ( -4--3-1---14-2-12)

+2.1+×3.5×2.2×+9.8 ( +2.1+×3.5×2.2×++2.1+7.7+9.8)

×3×÷-0-6-÷2÷×-9 ( ×3×÷-0-6-÷2÷××3×÷¯6÷2÷××3ׯ3ׯ9)

÷4÷-3-÷1÷2÷-÷1.6 ( ÷4÷-3-÷1÷2÷-÷÷4÷-3-0.5-÷÷4÷2.5÷1.6)

Adão
fonte
1
The explanations below use high minus (`¯`) to indicate negative numbers.Você definitivamente ama APL.
Erik the Outgolfer
@EriktheOutgolfer Você tem uma sugestão melhor? Além disso, o TI-BASIC usa alto menos.
Adám
Na verdade, não porque -s pode ser confundido com -s enquanto ¯s não pode ser confundido com -s.
Erik the Outgolfer
Bah, acabei de notar o requisito de número real. Tanto para o meu 290-byte inteiro solução Retina aritmética ...
Neil
@ Neil Por que você não o publica como resposta?
Adám

Respostas:

4

C # (.NET Core) , 198197188 bytes

float O(string s){try{return float.Parse(s);}catch{var f=s[0];int i=s.IndexOf(f,1);float a=O(s.Substring(1,i-1)),b=O(s.Substring(i+1,s.Length-i-2));return f<43?a*b:f<44?a+b:f<46?a-b:a/b;}}

Experimente online!

Usos *e /.

Uma função recursiva. Primeiro, ele tenta analisar a sequência de entrada como a float. Se falhar, chama a si próprio passar recursivamente como argumentos o primeiro e o segundo operandos e, em seguida, executa a operação selecionada nos resultados.

  • 1 byte economizado graças ao Sr. Xcoder!
  • 9 bytes salvos graças ao TheLethalCoder!
Charlie
fonte
IndefOf(f, 1)pode serIndexOf(f,1)
Sr. Xcoder
1
Use floats em vez disso, use os códigos de caracteres, quando você os tiver provavelmente poderá encurtá-los com >e <em alguns lugares.
TheLethalCoder
Você pode jogar um byte de golfe mudando i+1,s.Length-i-2para ++i,s.Length+~i.
Kevin Cruijssen
4

Python 3, 159 158 152 144 144 135 135 132 bytes

def t(i,a=1):
 while'-'<l[i]!='/':i+=1;a=0
 if a:l[i]='(';i=t(t(i+1));l[i-1]=')'
 return-~i
*l,=input()
t(0)
print(eval(''.join(l)))

Experimente online!

Não permite números negativos (embora -0-5-funcione, é claro) e requer operadores python.

Arfie
fonte
Você pode adicionar um link TIO?
Adám
1
while~-(l[i]in'+-*/'):i+=1;a=1e *l,=input()para 152 bytes
Felipe Nardi Batista
1
com todos os casos de teste: link
Felipe Nardi Batista
1
144 bytes
Felipe Nardi Batista
1
if a:l[i]='(';i=t(t(i+1));l[i-1]=')'com return-~i135 bytes: P
Felipe Nardi Batista
3

Retina , 290 287 286 bytes

\d+
¦$&$*
¯¦
¯
{`\+([¯¦]1*)\+([¯¦]1*)\+
-$1-¯$2-
-(¯|¦)(1*)-([¯¦]+1*\2)-
-¯$3-¯$1$2-
(×|÷)¯(1*\1)([¯¦]1*\1)
$1¦$2¯$3
צ×[¯¦]1*×|¯¯¦?
¦
¯¦|¦¯
¯
+`-((¯|¦)1*)(1*)-\2\3-
$1
-([¯¦]1*)-[¯¦](1*)-
$1$2
צ1(1*)×([¯¦]1*)×
+צ$1×$2×+$2+
}`÷¦(?=1*÷(¯|¦)(1+)÷)(\2)*1*÷\1\2÷
$1$#3$*
((¯)|¦)(1*)
$2$.3

Experimente online! Nota: Somente capaz de aritmética inteira, portanto, alguns dos casos de teste foram removidos. Aceita e retorna números negativos usando o ¯prefixo. Edit: Salvo 3 4 bytes graças ao @Cowsquack. Explicação:

\d+
¦$&$*

Eu precisava de uma maneira de lidar com zero, então eu uso ¦como um prefixo de número positivo. Os números são convertidos para unários.

¯¦
¯

Mas números negativos precisam apenas de um ¯prefixo.

{`\+([¯¦]1*)\+([¯¦]1*)\+
-$1-¯$2-

Citar +s fica feio, então eu transformei adições em subtrações.

-(¯|¦)(1*)-([¯¦]+1*\2)-
-¯$3-¯$1$2-

Se o valor absoluto do LHS de uma subtração for menor que o RHS, troque-os e anule os dois lados.

(×|÷)¯(1*\1)([¯¦]1*\1)
$1¦$2¯$3

Além disso, se o LHS de uma multiplicação ou divisão for negativo, negue os dois lados.

צ×[¯¦]1*×|¯¯¦?
¦

Além disso, se o LHS de uma multiplicação for zero, o resultado será zero. Além disso, dois menos fazem uma vantagem.

¯¦|¦¯
¯

Mas um sinal de menos e um sinal de mais (ou vice-versa) fazem um sinal de menos.

+`-((¯|¦)1*)(1*)-\2\3-
$1

Subtraia dois números do mesmo sinal. Faça isso repetidamente até que não haja mais subtrações.

-([¯¦]1*)-[¯¦](1*)-
$1$2

Se ainda houver uma subtração, os sinais devem ser diferentes, então adicione os números. (Mas faça isso apenas uma vez, pois isso poderá revelar uma subtração de dois números do mesmo sinal novamente.)

צ1(1*)×([¯¦]1*)×
+צ$1×$2×+$2+

Realize a multiplicação por adição repetida.

}`÷¦(?=1*÷(¯|¦)(1+)÷)(\2)*1*÷\1\2÷
$1$#3$*

Execute a divisão inteira. Uma das etapas acima terá simplificado a expressão, portanto, retorne até que não haja mais operações.

((¯)|¦)(1*)
$2$.3

Converta de volta para decimal.

Neil
fonte
Uau, isso é épico. Maior publicação de Retina sobre PPCG? No entanto, geralmente as soluções QuadR e Retina se parecem muito.Posso inspirar?
Adám
Nesta linha +`-(([¯¦])1*)(1*)-\2\3-, [¯¦]pode se tornar¯|¦
Kritixi Lithos
@Cowsquack acontece três vezes, de fato, obrigado!
Neil
Você perdeu ([×÷]);)
Kritixi Lithos 2/17/17
1
@Cowsquack É melhor você não encontrar um outro, caso contrário, eu vou ter que atravessar a 4 ...
Neil
2

PHP , 116 114 109 bytes

-5 graças a Martin Ender

for($s=$argv[$o=1];$o!=$s;)$s=preg_replace('#([*+/-])(([\d.]+|(?R))\1(?3))\1#','($2)',$o=$s);eval("echo$s;");

Usa *para multiplicação e /divisão. Acontece que números negativos funcionam, apesar de eu não fazer nenhuma tentativa específica para que isso aconteça.

Experimente online!

Ungolfed e Explained

for($s=$argv[$o=1];   # Initialize with $s = input and $o = 1;
    $o!=$s;)          # While $o != $s
    # Set $o to $s and set $s to be $s after this regex replacement:
    $s=preg_replace('#([*+/-])(([\d.]+|(?R))\1(?3))\1#','($2)',$o=$s);
    # i.e., continue to do this replacement until the result is the same on two consecutive
    # steps (no replacement was made)
# Once $o == $s (i.e. no more replacement can be made), eval the result and print
eval("echo$s;"); 

Também vou explicar o regex porque é um pouco mágico:

([*+/-])(([\d.]+|(?R))\1(?3))\1


([*+/-])

Primeiro, queremos corresponder a qualquer um dos quatro operadores: *+/-

([\d.]+|(?R))

Então, precisamos corresponder um número [\d.]+ou outra expressão omnifixo válida (?R).

\1

Então, combinamos o mesmo operador que estava no começo.

(?3)

Em seguida, fazemos o mesmo que fizemos no grupo 3: corresponde a um número ou a uma expressão omnifixa.

\1

Finalmente, combine o operador inicial novamente.

O que quer que corresponda a isso é substituído por ($2). Isso pega a peça dentro dos operadores circundantes e a coloca entre colchetes, para que pareça uma notação infix normal.

Gato de negócios
fonte
2

QuadR , 33 32 27 bytes

-1 graças a Vacas Quack . -5 graças a Erik, o Outgolfer .

((.)[\d¯\.]+){2}\2
⍎¯11↓⍵M

com o argumento / flag

Experimente online!

Isso é equivalente à solução Dyalog APL de 40 bytes:

'((.)[\d¯\.]+){2}\2'R{⍕⍎1↓¯1↓⍵.Match}⍣≡

Experimente online!

Explicação

(o texto entre parênteses refere-se ao Dyalog APL em vez de QuadR)

(){2}\2 O seguinte padrão duas vezes e o conjunto também duas vezes:
  (.) qualquer caractere
  []+ seguido por um ou mais dos seguintes conjuntos de caracteres:
   \dd igits,
   ¯ high menos (sinal negativo)
   \.  período

( ⎕R É R eplaced com :)

( {} O resultado da seguinte função anônima aplicada ao namespace ⍵ :)

⍵M ( ⍵.Match) O texto do M atch
¯1↓ soltar o último caractere (o símbolo + - ×ou ÷)
1↓ cair o primeiro caractere (símbolo)
 executar como código APL
 (  stringify)

 ( ⍣≡) repita a substituição até que não ocorram mais alterações

Adão
fonte
Eu acho que você pode largar
Kritixi Lithos
@ Cowquack Você está certo sobre o QuadR. ⎕Rnão pode operar com dados numéricos. Obrigado.
Adám
Regex mais curto; -5 bytes.
Erik the Outgolfer
1

Haskell , 132 caracteres

(134 bytes, porque ×e ÷tomar dois bytes em UTF-8)

f y|(n@(_:_),r)<-span(`elem`['.'..'9'])y=(read n,r)
f(c:d)|(l,_:s)<-f d,(m,_:r)<-f s=(o[c]l m,r)
o"+"=(+)
o"-"=(-)
o"×"=(*)
o"÷"=(/)

Experimente online!

fanalisa o máximo de entrada possível e produz o resultado, bem como a sequência restante (que está vazia nos casos de teste). Se isso não estiver em conformidade com as regras, descasque a sequência restante imperceptível com

Haskell , 139 caracteres

...
g=fst.f
deixou de girar contra-relógio
fonte
0

Perl, 64 53 bytes

Incluir +1para-p

perl -pe 's%([*-/])(([\d.]+|(?0))\1(?3))\1%($2)%&&redo;$_=eval' <<< "/4/-3-/1/2/-/"

Acidentalmente também implementa ,(joga fora o primeiro argumento) e algumas vezes .(acrescenta os argumentos). .embora não funcione muito confiável, pois interfere no ponto decimal no nível de análise e no nível de avaliação

Ton Hospel
fonte
0

Java 8, 205 200 bytes

float O(String s){try{return new Float(s);}catch(Exception e){int f=s.charAt(0),i=s.indexOf(f,1);float a=O(s.substring(1,i)),b=O(s.substring(i+1,s.length()-1));return f<43?a*b:f<44?a+b:f<46?a-b:a/b;}}

Porto de @Charlie resposta # 's C .
-5 bytes graças a @ceilingcat .

Experimente online.

Kevin Cruijssen
fonte