2010-07-21 10 views
10

¿Cuál es la forma más eficiente para convertir cantidad numérica dentro de palabras en inglésalgoritmo que convierte la cantidad numérica dentro de palabras en inglés

por ejemplo, 12 a doce 127 a ciento veintisiete

+2

O en inglés cien ** y ** veintisiete. :) –

+1

@Philip, el "y" es incorrecto si estás hablando del inglés correcto. "Y" es para partes fraccionales. –

+1

@David - En inglés británico, si un número incluye un número más pequeño ** y ** se une a ellos. Como en 2010, dos mil diez. Otra variación está en la moneda cuando £ 1.20 es una libra veinte o una libra y veinte peniques. Si está aburrido puede ver http://www.english-at-home.com/speaking/saying-dates-and-numbers-in-english/ –

Respuesta

16

Eso no llevó mucho tiempo. Esta es una implementación escrita en Java.

http://snippets.dzone.com/posts/show/3685

Código

public class IntToEnglish { 
    static String[] to_19 = { "zero", "one", "two", "three", "four", "five", "six", 
     "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", 
     "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen" }; 
    static String[] tens = { "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"}; 
    static String[] denom = { "", 
     "thousand",  "million",   "billion",  "trillion",  "quadrillion", 
     "quintillion", "sextillion",  "septillion", "octillion",  "nonillion", 
     "decillion", "undecillion",  "duodecillion", "tredecillion", "quattuordecillion", 
     "sexdecillion", "septendecillion", "octodecillion", "novemdecillion", "vigintillion" }; 

    public static void main(String[] argv) throws Exception { 
     int tstValue = Integer.parseInt(argv[0]); 
     IntToEnglish itoe = new IntToEnglish(); 
     System.out.println(itoe.english_number(tstValue)); 
     /* for (int i = 0; i < 2147483647; i++) { 
      System.out.println(itoe.english_number(i)); 
     } */ 
    } 
    // convert a value < 100 to English. 
    private String convert_nn(int val) throws Exception { 
     if (val < 20) 
      return to_19[val]; 
     for (int v = 0; v < tens.length; v++) { 
      String dcap = tens[v]; 
      int dval = 20 + 10 * v; 
      if (dval + 10 > val) { 
       if ((val % 10) != 0) 
        return dcap + "-" + to_19[val % 10]; 
       return dcap; 
      }   
     } 
     throw new Exception("Should never get here, less than 100 failure"); 
    } 
    // convert a value < 1000 to english, special cased because it is the level that kicks 
    // off the < 100 special case. The rest are more general. This also allows you to 
    // get strings in the form of "forty-five hundred" if called directly. 
    private String convert_nnn(int val) throws Exception { 
     String word = ""; 
     int rem = val/100; 
     int mod = val % 100; 
     if (rem > 0) { 
      word = to_19[rem] + " hundred"; 
      if (mod > 0) { 
       word = word + " "; 
      } 
     } 
     if (mod > 0) { 
      word = word + convert_nn(mod); 
     } 
     return word; 
    } 
    public String english_number(int val) throws Exception { 
     if (val < 100) { 
      return convert_nn(val); 
     } 
     if (val < 1000) { 
      return convert_nnn(val); 
     } 
     for (int v = 0; v < denom.length; v++) { 
      int didx = v - 1; 
      int dval = new Double(Math.pow(1000, v)).intValue(); 
      if (dval > val) { 
       int mod = new Double(Math.pow(1000, didx)).intValue(); 
       int l = val/mod; 
       int r = val - (l * mod); 
       String ret = convert_nnn(l) + " " + denom[didx]; 
       if (r > 0) { 
        ret = ret + ", " + english_number(r); 
       } 
       return ret; 
      } 
     } 
     throw new Exception("Should never get here, bottomed out in english_number"); 
    } 
} 
2

Una forma de lograr esto sería el uso de tablas de consulta. Sería algo así como fuerza bruta, pero fácil de configurar. Por ejemplo, podría tener las palabras para 0-99 en una tabla, luego una tabla para decenas, cientos, miles, etc. Algunas matemáticas simples le darán el índice de la palabra que necesita de cada tabla.

+0

Eso sería un gran desperdicio de memoria. – Christian

+0

Estoy de acuerdo con su evaluación pero utilicé el término "fuerza bruta" en mi descripción. Además, hay otras respuestas para esta misma pregunta que utilizan un enfoque de tabla de búsqueda, incluida la respuesta aceptada. No estoy seguro de por qué tu comentario solo se aplica a mi respuesta. – nathan

1

.) Crea una biblioteca de todos los números & posiciones (por ejemplo 1 tiene otra anotación de 10, otra de 100, etc.) .) Hacer una lista de excepciones (por ejemplo, para 12) y tener en cuenta, que en su algoritmo, la misma excepción es para 112, 1012, etc.

si quiere aún más velocidad, haga un conjunto de números en caché que necesite.

1

Nota algunas reglas:

números
  • decenas (veinte, treinta, etc.) que terminan en y son seguidos por guiones.
  • Los adolescentes son especiales (excepto 15-19, pero todavía son especiales).
  • Todo lo demás es solo una combinación de digit place como "tres mil".

Puede obtener el lugar de un número mediante la división de enteros planta: 532/100 -> 5

2

Este es un viejo código Python en mi disco duro. Puede haber errores pero debería mostrar la idea básica:

class Translator: 
    def transformInt(self, x): 
     translateNumbers(0,[str(x)]) 

    def threeDigitsNumber(self,number): 
     snumber=self.twoDigitsNumber(number/100) 
     if number/100!=0: 
      snumber+=" hundred " 
     snumber+self.twoDigitsNumber(number) 
     return snumber+self.twoDigitsNumber(number) 
    def twoDigitsNumber(self,number): 
     snumber="" 
     if number%100==10: 
      snumber+="ten" 
     elif number%100==11: 
      snumber+="eleven" 
     elif number%100==12: 
      snumber+="twelve" 
     elif number%100==13: 
      snumber+="thirteen" 
     elif number%100==14: 
      snumber+="fourteen" 
     elif number%100==15: 
      snumber+="fifteen" 
     elif number%100==16: 
      snumber+="sixteen" 
     elif number%100==17: 
      snumber+="seventeen" 
     elif number%100==18: 
      snumber+="eighteen" 
     elif number%100==19: 
      snumber+="nineteen" 
     else: 
      if (number%100)/10==2: 
       snumber+="twenty-" 
      elif (number%100)/10==3: 
       snumber+="thirty-" 
      elif (number%100)/10==4: 
       snumber+="forty-" 
      elif (number%100)/10==5: 
       snumber+="fifty-" 
      elif (number%100)/10==6: 
       snumber+="sixty-" 
      elif (number%100)/10==7: 
       snumber+="seventy-" 
      elif (number%100)/10==8: 
       snumber+="eighty-" 
      elif (number%100)/10==9: 
       snumber+="ninety-" 
      if (number%10)==1: 
       snumber+="one" 
      elif (number%10)==2: 
       snumber+="two" 
      elif (number%10)==3: 
       snumber+="three" 
      elif (number%10)==4: 
       snumber+="four" 
      elif (number%10)==5: 
       snumber+="five" 
      elif (number%10)==6: 
       snumber+="six" 
      elif (number%10)==7: 
       snumber+="seven" 
      elif (number%10)==8: 
       snumber+="eight" 
      elif (number%10)==9: 
       snumber+="nine" 
      elif (number%10)==0: 
       if snumber!="": 
        if snumber[len(snumber)-1]=="-": 
         snumber=snumber[0:len(snumber)-1] 
     return snumber 
    def translateNumbers(self,counter,words): 
     if counter+1<len(words): 
      self.translateNumbers(counter+1,words) 
     else: 
      if counter==len(words): 
       return True 
     k=0 
     while k<len(words[counter]): 
      if (not (ord(words[counter][k])>47 and ord(words[counter][k])<58)): 
       break 
      k+=1 
     if (k!=len(words[counter]) or k==0): 
      return 1 
     number=int(words[counter]) 
     from copy import copy 
     if number==0: 
      self.translateNumbers(counter+1,copy(words[0:counter]+["zero"]+words[counter+1:len(words)])) 
      self.next.append(copy(words[0:counter]+["zero"]+words[counter+1:len(words)])) 
      return 1 
     if number<10000: 
      self.translateNumbers(counter+1,copy(words[0:counter] 
                 +self.seperatewords(self.threeDigitsNumber(number)) 
                 +words[counter+1:len(words)])) 
      self.next.append(copy(words[0:counter] 
             +self.seperatewords(self.threeDigitsNumber(number)) 
             +words[counter+1:len(words)])) 
     if number>999: 
      snumber="" 
      if number>1000000000: 
       snumber+=self.threeDigitsNumber(number/1000000000)+" billion " 
       number=number%1000000000 
      if number>1000000: 
       snumber+=self.threeDigitsNumber(number/1000000)+" million " 
       number=number%1000000 
      if number>1000: 
       snumber+=self.threeDigitsNumber(number/1000)+" thousand " 
       number=number%1000 
      snumber+=self.threeDigitsNumber(number) 
      self.translateNumbers(counter+1,copy(words[0:counter]+self.seperatewords(snumber) 
                 +words[counter+1:len(words)])) 
      self.next.append(copy(words[0:counter]+self.seperatewords(snumber) 
             +words[counter+1:len(words)])) 
2

Esta solución no intenta dar cuenta de los espacios finales, pero es bastante rápido.

typedef const char* cstring; 
using std::string; 
using std::endl; 
std::ostream& GetOnes(std::ostream &output, int onesValue) 
{ 
    cstring ones[] = { "zero", "one", "two", "three", "four", "five", "six", 
      "seven", "eight", "nine" }; 
    output << ones[onesValue]; 
    return output; 
} 

std::ostream& GetSubMagnitude(std::ostream &output, int subMagnitude) 
{ 
    cstring tens[] = { "zeroty", "ten", "twenty", "thirty", "fourty", "fifty", 
     "sixty", "seventy", "eighty", "ninety"}; 
    if (subMagnitude/100 != 0) 
    {  
     GetOnes(output, subMagnitude/100) << " hundred "; 
     GetSubMagnitude(output, subMagnitude - subMagnitude/100 * 100); 
    } 
    else 
    { 
     if (subMagnitude >= 20) 
     { 
      output << tens[subMagnitude/10] << " "; 
      GetOnes(output, subMagnitude - subMagnitude/10 * 10); 
     } 
     else if (subMagnitude >= 10) 
     { 
      cstring teens[] = { "ten", "eleven", "twelve", "thirteen", 
         "fourteen", "fifteen", "sixteen", "seventeen", 
         "eighteen", "nineteen" }; 
      output << teens[subMagnitude - 10] << " "; 
     } 
     else 
     { 
      GetOnes(output, subMagnitude) << " "; 
     } 
    } 
    return output; 
} 

std::ostream& GetLongNumber(std::ostream &output, double input) 
{ 
    cstring magnitudes[] = {"", "hundred", "thousand", "million", "billion", 
          "trillion"}; 
    double magnitudeTests[] = {1, 100.0, 1000.0, 1000000.0, 1000000000.0, 
          1000000000000.0 }; 
    int magTestIndex = 0; 
    while (floor(input/magnitudeTests[magTestIndex++]) != 0); 
    magTestIndex -= 2; 
    if (magTestIndex >= 0) 
    { 
     double subMagnitude = input/magnitudeTests[magTestIndex]; 
     GetSubMagnitude(output, (int)subMagnitude); 
     if (magTestIndex) { 
      output << magnitudes[magTestIndex] << " "; 
      double remainder = input - (floor(input/
         magnitudeTests[magTestIndex]) * 
         magnitudeTests[magTestIndex]); 
      if (floor(remainder) > 0) 
      { 
       GetLongNumber(output, remainder); 
      } 
     } 
    } 
    else 
    { 
     output << "zero"; 
    } 
    return output; 
} 
+0

Obviamente, las renuncias de responsabilidad incluyen que no cuenta para números mayores a 999,999,999,999,999, no hace fracciones y no maneja números negativos. Lo suficientemente fácil de agregar, pero tienes que parar en algún punto. –

2

de inicio mediante la resolución 1-99, utilizando una lista de números de 1-20, y luego 30, 40, ..., 90. A continuación, añadir cientos de conseguir 1-999. Luego use esa rutina para dar el número de cada potencia de 1,000 tan alto como desee (creo que la nomenclatura estándar más alta es para decillion, que es 10^33).

Una pequeña advertencia es que es un poco complicado conseguir los espacios en blanco en todos los casos si está tratando de comenzar y terminar sin un exceso de espacio en blanco. La solución más fácil es poner un espacio en blanco después de cada palabra, y luego quitar el espacio en blanco al terminar. Si intentas ser más preciso al construir la cuerda, es probable que termines con espacios en blanco o espacios en blanco faltantes.

Cuestiones relacionadas