Calculadora redactada

14

Una versión simplista de la calculadora numérica inglesa

Tarea

Escriba un programa que tome una cadena como entrada y genere el resultado de la expresión.

Reglas

La cadena de entrada estará redactada y no será numérica.

No habrá paréntesis.

El orden de cálculo será dividir, multiplicar, restar y luego sumar.

Para las mismas operaciones, los cálculos deben hacerse de izquierda a derecha.

Todos los números de entrada serán enteros de -999 a 999 (ambos incluidos)

La salida será un número entero de cualquier rango.

La división siempre será perfectamente divisible y cero nunca será un denominador.

La restricción de mayúsculas y minúsculas para la entrada es opcional. No tiene que verificar la validez de la entrada.

Formato numérico

0 to 20 -> zero,one,two...nineteen,twenty
21 to 99 -> twenty one,twenty two.....ninety eight,ninety nine
100 to 999 -> one hundred, one hundred one, one hundred two...one hundred ten....two hundred fifty....nine hundred ninety eight,nine hundred ninety nine

Para números negativos: agregue minusa su equivalente positivo

Formato de operación

Addition: one plus two
Subtraction: one minus two
Multiplication: one time two #Note that for one on the left of multiplication, it is one time and not times.
                two times one hundred
Division: forty divided by two

Ejemplos:

o/p <- input

20     four times five
35     twenty plus fifteen
70     fifty plus five times four
-90    minus one time ninety
25     twenty one minus minus four
45     ninety divided by two
700    one time seven hundred 
555    one hundred eleven times two plus three hundred thirty three
99     one hundred plus minus one
45     forty five plus two hundred times zero
 4     four
-3     three minus three minus three

Este es el código de golf, por lo que el código más corto gana

Vedant Kandoi
fuente
1
¿Duplicar? - Creo que está lo suficientemente cerca como para ser considerado como tal.
Kirill L.
2
Está muy cerca de hecho. Pero creo que este está mejor especificado y tiene limitaciones más razonables.
Arnauld
1
@Arnauld Mantendré esto abierto, pero si otros piensan de manera diferente, solo márquelo como duplicado.
Vedant Kandoi
15
Yo digo one times two. ¿Está usando timenormal?
Jo King
2
Creo que quisiste decir 'una vez s setecientos'?
ouflak

Respuestas:

18

JavaScript (ES6), 257 252 249 235 bytes

Guardado 3 bytes gracias a @Shaggy

s=>eval(s.split` `.map(w=>(i='zeonwohrr44fx3n5t54nn3leel8tou7fn7n98etetwthfofisiseeinihuplmitidiby'.match(/../g).findIndex(x=>~(w+w.length+w).search(x)))>28?n+' '+'+-*/ '[n='',i-29]:(n=+n+(i<28?i<20?i:i*10-180:n*99),''),n='').join``+n)

Pruébalo en línea!

¿Cómo?

WLyoW+L+W .

Números

 index | word              | word + length + word         | key substring
-------+-------------------+------------------------------+---------------
    0  | "zero"            | "zero4zero"                  | "ze"
    1  | "one"             | "one3one"                    | "on"
    2  | "two"             | "two3two"                    | "wo"
    3  | "three"           | "three5three"                | "hr"
    4  | "four"            | "four4four"                  | "r4"
    5  | "five"            | "five4five"                  | "4f"
    6  | "six"             | "six3six"                    | "x3"
    7  | "seven"           | "seven5seven"                | "n5"
    8  | "eight"           | "eight5eight"                | "t5"
    9  | "nine"            | "nine4nine"                  | "4n"
   10  | "ten"             | "ten3ten"                    | "n3"
   11  | "eleven"          | "eleven6eleven"              | "le"
   12  | "twelve"          | "twelve6twelve"              | "el"
   13  | "thirteen"        | "thirteen8thirteen"          | "8t"
   14  | "fourteen"        | "fourteen8fourteen"          | "ou"
   15  | "fifteen"         | "fifteen7fifteen"            | "7f"
   16  | "sixteen"         | "sixteen7sixteen"            | "n7"
   17  | "seventeen"       | "seventeen9seventeen"        | "n9"
   18  | "eighteen"        | "eighteen8eighteen"          | "8e"
   19  | "nineteen"        | "nineteen8nineteen"          | "te"
   20  | "twenty"          | "twenty6twenty"              | "tw"
   21  | "thirty"          | "thirty6thirty"              | "th"
   22  | "forty"           | "forty5forty"                | "fo"
   23  | "fifty"           | "fifty5fifty"                | "fi"
   24  | "sixty"           | "sixty5sixty"                | "si"
   25  | "seventy"         | "seventy7seventy"            | "se"
   26  | "eighty"          | "eighty6eighty"              | "ei"
   27  | "ninety"          | "ninety6ninety"              | "ni"
   28  | "hundred"         | "hundred7hundred"            | "hu"

Operadores

 index | word              | word + length + word         | key substring
-------+-------------------+------------------------------+---------------
   29  | "plus"            | "plus4plus"                  | "pl"
   30  | "minus"           | "minus5minus"                | "mi"
   31  | "times" or "time" | "times5times" or "time4time" | "ti"
   32  | "divided"         | "divided7divided"            | "di"
   33  | "by"              | "by2by"                      | "by"

Interpretación

norteyo

i > 28 ?                  // if the word is an operator:
  n +                     //   append n (which is either an empty string or a number)
  ' ' +                   //   append a space
  '+-*/ '[n = '', i - 29] //   reset n to an empty string and append the operator
                          //   the useless keyword 'by' is translated into a harmless space
: (                       // else:
    n =                   //   update n:
      +n + (              //     force the coercion of the current value of n to a number
        i < 28 ?          //     if the word is not 'hundred':
          i < 20 ?        //       if the value of the word is less than 'twenty':
            i             //         add i
          :               //       else:
            i * 10 - 180  //         add i * 10 - 180 (e.g. 'fifty' -> 23 * 10 - 180 = 50)
        :                 //     else:
          n * 99          //       multiply n by 100 by adding 99 * n to itself
      ),                  //
    ''                    //   remove this word from the original string
  )                       //
Arnauld
fuente
11

Perl 6 , 170 139 129 128 124 122 bytes

-13 bytes gracias a nwellnhof!

{S:g/(<:N>+)+%\s/({'+'X$0})/.EVAL}o{S:g/" ҈"/00/}o{TR"⁢ʼn؊⟠"*/൰ "}o*.words>>.&{chr first *.uniname.comb(.uc),1..*}

Pruébalo en línea!

univalal rescate otra vez! Esto (actualmente) incluso supera a los idiomas de golf como05AB1E !

Explicación:

*.words     # Split by word boundaries (in this case spaces)
       >>.{                            }  # Map each word to
           chr first             ,1..*    # The first character where:
                     *.uniname      # The unicode name of that character
                                    # e.g. DIGIT FIVE
                      .comb(.uc)    # Contains the uppercase of the word
{             }o  # Pass this list to another function
                  # That converts the list to a string
 TR"⁢ʼn؊⟠"*/൰ "    #"# And parse out the garbage characters that were wrong
                  # INVISIBLE TIMES => "*"
                  # LOZENGE DIVIDED BY HORIZONTAL RULE => "/"
                  # ARABIC-INDIC PER TEN THOUSAND SIGN => "൰" (value ten)
                  # LATIN SMALL LETTER N PRECEDED BY APOSTROPHE => " "
{S:g/" ҈"/00/}o   # Replace the character for "hundred" with 00

{                                }o   # And finally combine with
 S:g/(<:N>+)+%\s/   # Substitute each number-like character separated by spaces
                /({'+'X$0})/   # With the numbers prefixed by '+'s, in brackets
               # This works because Perl 6 supports numeric unicode literals, like
               # ፳ => 20, ፴ => 30, ፺ => 90, etc.
                            .EVAL   # And finally evaluate the whole expression
Jo King
fuente
7

Python 2 , 333 ... 284 277 275 bytes

lambda s:eval(''.join((list('+-/*')+[`N(w,0)*100+N(w,2)`])['pmdt'.find(w)]for w in re.split(' *(?:(p|m)|(t|d)i|by).*? ',s)if w))
N=lambda x,y:sum(10*(w[-3:]in'lveen')+'zeontwthfofisiseeiniteel'.find(w[:2])/2*10**('y'in w)for w in x.rpartition('hundred')[y].split())
import re

Pruébalo en línea!

TFeld
fuente
5

Wolfram Language 95 94 82 bytes

Interpreter["SemanticExpression"][#~StringReplace~{"me "->"mes ","plus m"->"m"}]&

# representa la entrada para la función pura.

Si es necesario, StringReplacesustituye a "tiempo" con los tiempos " 'más menos' con 'menos' (a través de "me "->"mes ", "plus m"->"m", respectivamente). Los formularios de reemplazo acortados, sugeridos por lirtosiast, guardaron 12 bytes.

Interpreter["SemanticExpression"] hace todo el resto

DavidC
fuente
Se puede cambiar "time "->"times "a "me"->"mes"y "plus minus"->"minus"a "plus m"->"m"?
lirtosiast el
Si. Excelentes sugerencias
DavidC
3

05AB1E , 166 147 141 139 135 bytes

„byK“¡×€µ‚•„í†ìˆÈŒšï¿Ÿ¯¥Š—¿áÓÁÏ“#vyN:}'tK'…§¦'+T«:'°¡„ *т«©:.•1×j›o!ĆÖ•3ôŽ9oS:'y®¨:©“‰´Øè„Æ€ººß“'tK#UX¡εð¡õK2ôJ.EO}®áX"+-**/"S:Sðì.ιJ.E

Demasiado tiempo. Intentaré jugar golf desde aquí.

-4 bytes gracias a @Emigna .
-2 bytes gracias a @JoKing .

Pruébalo en línea o verifique todos los casos de prueba .

Explicación:

byK                 # Remove "by" from the (implicit) input-string
“¡×€µ‚•„í†ìˆÈŒšï¿Ÿ¯¥Š—¿áÓÁÏ“
                     # Push string "zero one two three four five six seven eight nine ten eleven twelve"
 #                   # Split by spaces
  v   }              # Loop over each of these items:
   yN:               #  Replace the item with its 0-indexed index
'tK                 '# Remove all "t"
'…§¦                '# Push string "teen", and remove the first character: "een"
    '+              '# Push string "+"
      T«             # Append 10: "+10"
        :            # Replace all "een" with "+10"
'°¡                 '# Push string "hundred"
    *               # Push string " *"
      т«             # Append 100: " *100"
        ©            # Store it in the register (without popping)
         :           # Replace all "hundred" with " *100"
.•4º»Ÿć'Rþн•        '# Push string "wenhirforfif"
            3ô       # Split the string into parts of size 3: ["wen","hir","for","fif"]
              Ž9o    # Push integer 2345
                 S   # Split to digits: [2,3,4,5]
                  :  # Replace each
'y                  '# Push string "y"
  ®                  # Push the " *100" from the register
   ¨                 # Remove the last character: " *10"
    :                # Replace all "y" with " *10"
©                    # Save the current string in the register (without popping)
 “‰´Øè„Æ€ººß“        # Push string "plus minus times time divided"
             'tK    '# Remove all "t": "plus minus imes ime divided"
                #    # Split by spaces: ["plus","minus","imes","ime","divided"]
                 U   # Pop and save it in variable `X`
                  X  # And push variable `X` back again
                   ¡ # Split the string by those operator-strings
ε          }         # Map each substring to:
 ð¡                  #  Split by spaces (NOTE: cannot be `#`; if the string contains no
                     #   spaces, `#` remains string, whereas `ð¡` wraps it in a list)
   õK                #  Remove empty strings from the list
     2ô              #  Split the list into parts of two
       J             #  Join each pair together
        .E           #  Evaluate each as a Python `eval` expression
          O          #  Sum them
®                    # Put the string from the register to the stack again
 á                   # Remove everything except for letters
  X                  # Push variable `X`: ["plus","minus","imes","ime","divided"]
   "+-**/"           # Push string "+-**/"
          S          # Split to characters: ["+","-","*","*","/"]
           :         # Replace each
S                    # Split the string of operators to loose characters
 ðì                  # Prepend a space before each
                   # Interweave all sums with these operator-characters
     J               # Join everything together to a single string
.E                   # Evaluate each as a Python `eval` expression (and output implicitly)

Ver este consejo 05AB1E mío (secciones cómo utilizar el diccionario? , ¿Cómo comprimir cadenas que no forman parte del diccionario? Y Cómo comprimir grandes números enteros? ) Para entender cómo“¡×€µ‚•„í†ìˆÈŒšï¿Ÿ¯¥Š—¿áÓÁÏ“,'…§,'°¡,.•4º»Ÿć'Rþн•,Ž9o, y“‰´Øè„Æ€ººß“ el trabajo.

Ejemplo paso a paso:

  • Entrada: two hundred twenty two divided by two times minus fifty seven plus three hundred eighteen minus minus ten
  • Paso 1: Eliminar "por": two hundred twenty two divided two times minus fifty seven plus three hundred eighteen minus minus ten
  • Paso 2: Convierta "cero" a "doce" con el número correcto: 2 hundred twenty 2 divided 2 times minus fifty 7 plus 3 hundred 8een minus minus 10
  • Paso 3: eliminar todas las "t": 2 hundred weny 2 divided 2 imes minus fify 7 plus 3 hundred 8een minus minus 10
  • Paso 4: Reemplace todos los "een" con "+10": 2 hundred weny 2 divided 2 imes minus fify 7 plus 3 hundred 8+10 minus minus 10
  • Paso 5: Reemplace todos los "cien" con "* 100": 2 *100 weny 2 divided 2 imes minus fify 7 plus 3 *100 8+10 minus minus 10
  • Paso 6: Reemplace todos ["wen", "hir", "for", "fif"] con el dígito correcto: 2 *100 2y 2 divided 2 imes minus 5y 7 plus 3 *100 8+10 minus minus 10
  • Paso 7: Reemplace todas las "y" con "* 10": 2 *100 2 *10 2 divided 2 imes minus 5 *10 7 plus 3 *100 8+10 minus minus 10
  • Paso 8: dividir entre ["más", "menos", "ime", "imes", "dividido"]: ["2 *100 2 *10 2 "," 2 "," "," 5 *10 7 "," 3 *100 8+10 "," "," 10"]
  • Paso 9: Divida cada uno en espacios: [["2","","*100","2","*10","2",""],["","","2",""],["",""],["","5","*10","7",""],["","3","","*100","8+10",""],["",""],["","10"]]
  • Paso 10: eliminar elementos vacíos: [["2","*100","2","*10","2"],["2"],[],["5","*10","7"],["3","*100","8+10"],[],["10"]]
  • Paso 11: dividir en partes de tamaño 2 y unir: [["2*100","2*10","2"],["2"],"",["5*10","7"],["3*100","8+10"],"",["10"]]
  • Paso 12: Python evalcada uno:[[200,20,2],[2],"",[50,7],[300,18],"",[10]]
  • Paso 13: Suma cada uno: [222,2,"",57,318,"",10]
  • Paso 14: vuelva a empujar la cadena del registro y elimine todo excepto las letras dividedimesminusplusminusminus
  • Paso 15: Reemplace "más", "menos", "imes", "ime", "dividido" con los caracteres del operador y añádalos con un espacio: [" /"," *"," -"," +"," -"," -"]
  • Paso 16: entrelaza y une ambos: 222 /2 * -57 +318 - -10
  • Salida: Python evalla cadena, y salida implícitamente:-5999.0
Kevin Cruijssen
fuente
No he intentado hacer una solución desde cero o he estudiado la suya en detalle, pero noté un golf .
Emigna
@ Emmigna Gracias!
Kevin Cruijssen
2

sfk , 572 449 423 bytes

Todo esto podría ser una línea, pero para leerlo utilicé nuevas líneas en lugar de espacios.

xed -i
_plus_+_
_minus_-_
_times[ortext]time_*_
_divided?by_/_
+xed
"_[white][2 chars of a-z][chars of a-z]ty_[parts 1,2]0_"
"_[white][2 chars of a-z][chars of a-z]een_[part1]1[part2]_"
_ten_10_
_lev_11_
_twe_12_
+xed
_ze_0_
_on_1_
_tw_2_
_th_3_
_fo_4_
_fi_5_
_si_6_
_se_7_
_ei_8_
_ni_9_
+xed
_0[white][keep][digit]__
"_[chars of e-z ]__"
+xed
"_?dd[keep][2 digits]_[part1]_"
_?dd[keep][digit]_[part1]0_
_dd_00_
+calc #text

Pruébalo en línea!

Οurous
fuente