Créer une calculatrice omnifix

16

Inspiration. Inverse.

Évaluez une expression omnifix donnée.

Omnifix est comme la notation infixe des mathématiques normales, mais avec des copies supplémentaires de chaque symbole entourant les arguments. Les symboles extérieurs remplacent les parenthèses, et il n'est donc pas nécessaire d'avoir des parenthèses supplémentaires.

Vous devez prendre en charge l'addition, la soustraction, la multiplication, la division et les nombres réels positifs (des nombres négatifs peuvent être écrits -0-n-) dans une plage raisonnable pour votre langue.

Le plus et le moins doivent être +et -, mais vous pouvez utiliser *ou ×pour des temps et /ou ÷pour diviser. D'autres symboles raisonnables seront autorisés sur demande.

Brownie pointe pour des explications et des fonctionnalités supplémentaires (comme des opérations supplémentaires, des nombres négatifs, des chaînes, etc.) Même si votre réponse n'a pas ces fonctionnalités, n'hésitez pas à montrer comment cela pourrait.

Veuillez fournir un lien pour tester votre solution si possible.

Exemples

Pour plus de clarté, les explications ci-dessous utilisent un signe moins élevé ( ¯) pour indiquer des nombres négatifs. Vous pouvez renvoyer des nombres négatifs en utilisant n'importe quel format raisonnable.

-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)

Adam
la source
1
The explanations below use high minus (`¯`) to indicate negative numbers.Vous aimez vraiment APL.
Erik the Outgolfer
@EriktheOutgolfer Vous avez une meilleure suggestion? En outre, TI-BASIC utilise un signe moins élevé.
Adám
En fait pas puisque -s peut être confondu avec -s alors que ¯s ne peut pas être confondu avec -s.
Erik the Outgolfer
Bah, je viens de remarquer l'exigence du nombre réel. Voilà pour ma solution de rétine arithmétique de 290 octets ...
Neil
@Neil Pourquoi ne l'affichez-vous pas comme réponse?
Adám

Réponses:

4

C # (.NET Core) , 198197188 octets

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;}}

Essayez-le en ligne!

Utilise *et /.

Une fonction récursive. Il essaie d'abord d'analyser la chaîne d'entrée en tant que float. S'il échoue, il s'appelle lui-même en passant récursivement comme arguments les premier et second opérandes puis effectue l'opération sélectionnée sur les résultats.

  • 1 octet économisé grâce à M. Xcoder!
  • 9 octets économisés grâce à TheLethalCoder!
Charlie
la source
IndefOf(f, 1)peut êtreIndexOf(f,1)
M. Xcoder
1
Utilisez floats à la place, utilisez les codes de caractères, lorsque vous les avez, vous pouvez probablement les raccourcir avec >et <à quelques endroits.
TheLethalCoder
Vous pouvez jouer au golf un octet changeant i+1,s.Length-i-2à ++i,s.Length+~i.
Kevin Cruijssen
4

Python 3, 159 158 152 152 144 136 135 132 octets

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)))

Essayez-le en ligne!

Ne permet pas les nombres négatifs (bien que -0-5-fonctionne bien sûr) et nécessite des opérateurs python.

Arfie
la source
Pouvez-vous ajouter un lien TIO?
Adam
1
while~-(l[i]in'+-*/'):i+=1;a=1et *l,=input()pour 152 octets
Felipe Nardi Batista
1
avec tous les cas de test: lien
Felipe Nardi Batista
1
144 octets
Felipe Nardi Batista
1
if a:l[i]='(';i=t(t(i+1));l[i-1]=')'avec return-~ipour 135 octets: P
Felipe Nardi Batista
3

Rétine , 290 287 286 octets

\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

Essayez-le en ligne! Remarque: Uniquement capable d'arithmétique entière, donc certains des cas de test ont été supprimés. Accepte et renvoie des nombres négatifs en utilisant le ¯préfixe. Edit: enregistré 3 4 octets grâce à @Cowsquack. Explication:

\d+
¦$&$*

J'avais besoin d'un moyen de gérer zéro, donc j'utilise ¦comme préfixe de nombre positif. Les nombres sont ensuite convertis en unaires.

¯¦
¯

Mais les nombres négatifs n'ont besoin que d'un ¯préfixe.

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

Citer +s devient moche, donc je transforme les ajouts en soustractions.

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

Si la valeur absolue du LHS d'une soustraction est inférieure au RHS, inversez-les et annulez les deux côtés.

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

De plus, si le LHS d'une multiplication ou d'une division est négatif, annulez les deux côtés.

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

De plus, si le LHS d'une multiplication est nul, le résultat est nul. De plus, deux inconvénients font un plus.

¯¦|¦¯
¯

Mais un moins et un plus (ou vice versa) font un moins.

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

Soustrayez deux nombres du même signe. Répétez cette opération jusqu'à ce qu'il ne reste plus de soustractions.

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

S'il y a encore une soustraction, les signes doivent être différents, alors additionnez les nombres. (Mais ne faites cela qu'une seule fois, car cela peut révéler une soustraction de deux nombres du même signe à nouveau.)

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

Effectuer la multiplication par addition répétée.

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

Effectuez une division entière. L'une des étapes ci-dessus aura simplifié l'expression, donc bouclez jusqu'à ce qu'il ne reste aucune opération.

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

Reconvertissez en décimal.

Neil
la source
Wow, c'est - épique. Le plus grand message Retina sur PPCG? Cependant, les solutions QuadR et Retina se ressemblent généralement étroitement. Puis-je peut-être inspirer?
Adám
Dans cette lignée +`-(([¯¦])1*)(1*)-\2\3-, [¯¦]peut devenir¯|¦
Kritixi Lithos
@Cowsquack arrive trois fois en fait, merci!
Neil
Il y en a un que vous avez manqué ([×÷]);)
Kritixi Lithos
1
@Cowsquack Vous feriez mieux de ne pas en trouver un autre, sinon je vais devoir rayer 4 ...
Neil
2

PHP , 116 114 109 octets

-5 merci à Martin Ender

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

Utilise *pour la multiplication et /pour la division. Les nombres négatifs fonctionnent malgré que je ne fasse aucune tentative spécifique pour que ce soit le cas.

Essayez-le en ligne!

Non golfé et expliqué

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;"); 

Je vais aussi expliquer le regex car c'est un peu magique:

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


([*+/-])

Tout d'abord, nous voulons faire correspondre l'un des quatre opérateurs: *+/-

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

Ensuite, nous devons faire correspondre un nombre [\d.]+ou une autre expression omnifix valide (?R).

\1

Ensuite, nous faisons correspondre le même opérateur qu'au début.

(?3)

Ensuite, nous faisons la même chose que nous avons fait dans le groupe 3: faire correspondre un nombre ou une expression omnifix.

\1

Enfin, faites correspondre à nouveau l'opérateur initial.

Tout ce qui correspond est remplacé par ($2). Cela prend la partie à l'intérieur des opérateurs environnants et la place entre crochets, de sorte qu'elle ressemble à la notation infixe normale.

Chat d'affaires
la source
2

QuadR , 33 32 27 octets

-1 grâce à Cows Quack . -5 merci à Erik l'Outgolfer .

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

avec l'argument / drapeau

Essayez-le en ligne!

Cela équivaut à la solution Dyalog APL de 40 octets:

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

Essayez-le en ligne!

Explication

(le texte entre parenthèses fait référence à Dyalog APL au lieu de QuadR)

(... ){2}\2 le schéma suivant deux fois, et le tout le match deux fois trop:
  (.) tout caractère
  [... ]+ suivi par un ou plusieurs de l'ensemble des caractères suivants:
   \dd igits,
   ¯  MOINS (signe négatif)
   \. période

(⎕R  Est R eplaced avec :)

({} Le résultat de la fonction anonyme suivante appliquée à l'espace de noms ⍵ :)

⍵M ( ⍵.Match) le texte du M atch
¯1↓ supprime le dernier caractère (le symbole + - ×ou ÷)
1↓ supprime le premier caractère (symbole)
 exécute comme code APL
 (  stringify)

 ( ⍣≡) répéter le remplacement jusqu'à ce que plus aucun changement ne se produise

Adam
la source
Je pense que vous pouvez laisser tomber
Kritixi Lithos
@Cowsquack Vous avez raison sur QuadR. ⎕Rne peut pas fonctionner sur les données numériques. Merci.
Adám
Regex plus court; -5 octets.
Erik the Outgolfer le
1

Haskell , 132 caractères

(134 octets, car ×et ÷prenez deux octets en 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"÷"=(/)

Essayez-le en ligne!

fanalyse autant d'entrée que possible et produit le résultat ainsi que la chaîne restante (qui est vide dans les cas de test). Si ce n'est pas conforme aux règles, supprimez la chaîne restante non analysable avec

Haskell , 139 caractères

...
g=fst.f
a cessé de tourner dans le sens antihoraire
la source
0

Perl, 64 53 octets

Inclure +1pour-p

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

Accidentellement implémente également ,(jette le premier argument) et parfois .(ajoutez les arguments ensemble). .ne fonctionne pas très fiable, car il interfère avec le point décimal à la fois au niveau de l'analyse et au niveau de l'évaluation

Ton Hospel
la source
0

Java 8, 205 200 octets

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;}}

Port de la réponse C # de @Charlie .
-5 octets grâce à @ceilingcat .

Essayez-le en ligne.

Kevin Cruijssen
la source