Comunidad de diseño web y desarrollo en internet

Clase de Actionscript 3 para escribir números con palabras

Esta clase de actionscript 3 sirve para expresar un número con palabras. La api de esta clase se compone de 2 métodos estáticos llamados convertNumber y convertString, que reciben 2 parámetros:

  • Un número de tipo Number (convertNumber) ó un String (convertString), que será el número que queremos convertir. Acepta valores negativos, decimales (Ej: 1.818), y exponenciales (Ej: 1.1e99).
  • Un String que nos indicará el género del número devuelto (sólo veremos su efecto en las terminaciones de las centenas, y si el número acaba en 1, en cuyo caso devolverá "uno", "una" o "un" dependiendo del valor de este string). Este parámetro tiene 3 posibles valores, dados por las constantes estáticas de la propia clase NumberToWords GENDER_FEMALE, GENDER_MALE y GENDER_NONE.

La diferencia entre ambos métodos es que si usamos un Number, a partir de las centenas de trillón el número devuelto estará en formato exponencial, a partir del exponente 308 se considerará que el número es infinito, y además se hará un redondeo cuando el número tenga demasiados decimales.

Sin embargo si usamos convertString (usando un String en lugar de un número), se convertirá el número tal y como esté representado en la cadena de texto que introduzcamos, sin límite (aunque si introducimos más de 1000 cifras el cálculo se ralentiza un poco). A partir de las 100 cifras el número se interpretará como múltiplos de gúgol.

Ejemplo de uso:


Código :

import NumberToWords;

var number:Number = 21;
var strNumber:String = "80000000000000000000900000000000000000000000000000000000000000008000000000000000000000000000000000000000001";

trace(NumberToWords.convertNumber(number, NumberToWords.GENDER_FEMALE));
//veintiuna
trace(NumberToWords.convertNumber(number, NumberToWords.GENDER_NONE));
//veintiún
trace(NumberToWords.convertString(strNumber, NumberToWords.GENDER_MALE));
//ocho millones de gúgoles novecientos tetradecallones ocho septillones uno

En el siguiente swf se puede comprobar el funcionamiento de la clase. Hay que introducir el número a convertir en el TextArea superior, y en el inferior lo veremos expresado con palabras. Pulsando el botón “Abc” cambiamos el método que se utilizará para convertir el número (convertNumber o convertString), y con el otro botón cambiamos el género.

Código de la clase:


Código :

package
{
   public class NumberToWords
   {
      public static const GENDER_FEMALE:String = "genderFemale";
      public static const GENDER_MALE:String = "genderMale";
      public static const GENDER_NONE:String = "genderNone";
      private static const UNITS:Array = ["cero", "un", "dos", "tres", "cuatro", "cinco", "seis", "siete", "ocho", "nueve"];
      private static const TENS:Array = ["", "diez", "veinte", "treinta", "cuarenta", "cincuenta", "sesenta", "setenta", "ochenta", "noventa"];
      private static const TEN_TO_TWELVE:Array = ["", "once", "doce", "trece", "catorce", "quince", "dieciséis", "diecisiete", "dieciocho", "diecinueve"];
      private static const TWELVE_TO_THIRTY:Array = ["", "", "veintidós", "veintitrés", "veinticuatro", "veinticinco", "veintiséis", "veintisiete", "veintiocho", "veintinueve"];
      private static const HUNDREDS:Array = ["", "cient", "doscient", "trescient", "cuatrocient", "quinient", "seiscient", "setecient", "ochocient", "novecient"];
      private static const MILLIONS:Array = ["", "mill", "bill", "trill", "cuatrill", "quintill", "sextill", "septill", "octill", "nonill",
                                       "decall", "undecall", "dodecall", "tridecall", "tetradecall", "pentadecall", "hexadecall"];
      private static var wordsArray:Array;
      public static function convertNumber(number:Number, gender:String):String
      {
         //En caso de que no sea un número válido:
         if (isNaN(number)) return "No es un número";
         
         //Si el número es mayor que 1.79e+308 se considera infinito:
         if (number == Infinity) return "Infinito";
         
         //Llama a toWords para resolverlo convertido en String:
         return toWords(number.toString(), gender);
      }
      public static function convertString(inStr:String, gender:String):String
      {
         //En caso de que no sea un número válido:
         if (isNaN(Number(inStr))) return "No es un número";
         
         return toWords(inStr, gender);
      }
      private static function toWords(inStr:String, gender:String):String
      {
         //Vaciamos el array que irá guardando los resultados:
         wordsArray = [];
         
         var integerPart:String;
         var decimalPart:String;
         var exponentPart:String;
         
         //Divido el texto del número en las partes entera, decimal y exponencial:
         var splittedArray:Array = inStr.split("e");
         if (splittedArray.length == 2) exponentPart = splittedArray[1];
         
         splittedArray = splittedArray[0].split(".");
         if (splittedArray.length == 2) decimalPart = splittedArray[1];
         
         integerPart = splittedArray[0];
         
         //Resuelve la parte entera:
         solveIntegerPart(integerPart, gender);
         
         //Resuelve la parte decimal si la hay:
         if (decimalPart != null)
         {
            wordsArray.push("coma");
            solveDecimalPart(decimalPart);
         }
         
         //Resuelve la parte exponencial si la hay:
         if (exponentPart != null)
         {
            wordsArray.push("por diez elevado a la");
            wordsArray.push(solveIntegerPart(exponentPart, NumberToWords.GENDER_MALE));
         }
         
         //Devuelve los elementos del array unidos por espacios:
         return wordsArray.join(" ");
      }
      private static function solveDecimalPart(inStr:String):void
      {
         for (var i:uint = 0;i < inStr.length; i++)
         {
            //Los decimales siempre en masculino:
            solveUnits(inStr.charAt(i), NumberToWords.GENDER_MALE);
         }
      }
      private static function solveIntegerPart(inStr:String, gender:String):void
      {
         //Si el número es negativo, se añade menos al array y se convierte en valor absoluto:
         if (inStr.charAt(0) == "-")
         {
            wordsArray.push("menos");
            inStr = inStr.slice(1);
         }
         
         //Si el String comienza por "+" lo quitamos:
         if (inStr.charAt(0) == "+") inStr = inStr.slice(1);
         
         //Si el número es 0:
         if (Number(inStr) == 0)
         {
            wordsArray.push(UNITS[0]);
            return;
         }
         
         //Se resuelve el número natural resultante:
         solveNaturalPart(inStr, gender);
      }
      private static function solveNaturalPart(inStr:String, gender:String):void
      {
         //Esta función resolverá recursivamente las diferentes partes del número natural
         
         //Elimina todos los ceros a la izquierda:
         while(inStr.charAt(0) == "0")
         {
            inStr = inStr.slice(1);
         }
         
         //Si todo eran 0 sale de la función
         if (inStr == "") return;
         
         var integerLength:Number = inStr.length;
         
         if (integerLength > 100)
            solveGoogols(inStr, gender);
         else if (integerLength > 6)
            solveMillions(inStr, gender);
         else if (integerLength > 3)
            solveThousands(inStr, gender);
         else if (integerLength > 2)
            solveHundreds(inStr, gender);
         else if (integerLength > 1)
            solveTens(inStr, gender);
         else
            solveUnits(inStr, gender);
      }
      private static function solveGoogols(inStr:String, gender:String):void
      {
         var quotient:String = inStr.slice(0, -100);
         var remainder:String = inStr.slice(-100);
         
         //Para gúgoles el género es neutro:
         solveNaturalPart(quotient, NumberToWords.GENDER_NONE);
         
         //Si el cociente es 1 se usa gúgol y si no gúgoles:
         if (uint(quotient) == 1)
         {
            wordsArray.push("gúgol");
         }
         else
         {
            //Si los 6 dígitos anteriores a los gúgoles son 0, añade "de":
            if (quotient.length > 6 && uint(quotient.slice(-6)) == 0)
            {
               wordsArray.push("de");
            }
            wordsArray.push("gúgoles");
         }
         
         solveNaturalPart(remainder, gender);
      }
      private static function solveMillions(inStr:String, gender:String):void
      {
         var millionIndex:uint = Math.floor((inStr.length - 1) / 6);
         var quotient:String = inStr.slice(0, -millionIndex * 6);
         var remainder:String = inStr.slice(-millionIndex * 6);
         
         //Para iguales o superiores al millón, el género es neutro, porque se refiere al millón y no a lo que estemos contando:
         solveNaturalPart(quotient, NumberToWords.GENDER_NONE);
         
         //Si el cociente es 1 se usa la terminación en singular y si no en plural:
         if (uint(quotient) == 1)
         {
            wordsArray.push(MILLIONS[millionIndex] + "ón");
         }
         else
         {
            wordsArray.push(MILLIONS[millionIndex] + "ones");
         }
         
         solveNaturalPart(remainder, gender);
      }
      private static function solveThousands(inStr:String, gender:String):void
      {
         var quotient:String = inStr.slice(0, -3);
         var remainder:String = inStr.slice(-3);
         
         if (uint(quotient) > 1)
         {
            //El género femenino se trata de forma diferente al masculino y neutro:
            if (gender == NumberToWords.GENDER_MALE)
            {
               solveNaturalPart(quotient, NumberToWords.GENDER_NONE);
            }
            else
            {
               solveNaturalPart(quotient, gender);
            }
         }
         
         wordsArray.push("mil");
         solveNaturalPart(remainder, gender);
      }
      private static function solveHundreds(inStr:String, gender:String):void
      {
         var quotient:String = inStr.slice(0, -2);
         var remainder:String = inStr.slice(-2);
         
         //Si es 100 exacto devuelve cien:
         if (uint(inStr) == 100)
         {
            wordsArray.push("cien");
            return;
         }
         
         //En los demás casos:
         var suffix:String;
         if (uint(quotient) == 1)
         {
            //Si está entre 101 y 199 devuelve "ciento":
            suffix = "o";
         }
         else
         {
            //Si no devuelve doscientos/as, trescientos/as, ...
            suffix = (gender == NumberToWords.GENDER_FEMALE) ? "as" : "os";
         }
         
         wordsArray.push(HUNDREDS[uint(quotient)] + suffix);
         solveNaturalPart(remainder, gender);
      }
      private static function solveTens(inStr:String, gender:String):void
      {
         var quotient:String = inStr.slice(0, -1);
         var remainder:String = inStr.slice(-1);
         
         //21 tendrá diferentes valores según el género:
         if (uint(inStr) == 21)
         {
            switch (gender)
            {
               case NumberToWords.GENDER_FEMALE: 
                  wordsArray.push("veintiuna"); 
                  break;
               case NumberToWords.GENDER_MALE: 
                  wordsArray.push("veintiuno"); 
                  break;
               case NumberToWords.GENDER_NONE: 
                  wordsArray.push("veintiún"); 
                  break;
            }
            return;
         }
         
         //Si el residuo es 0 devuelve diez, veinte, treinta, ...
         if (uint(remainder) == 0)
         {
            wordsArray.push(TENS[uint(quotient)]);
            return;
         }
         
         //Si el cociente es 1 devuelve once, doce, trece, ...
         if (uint(quotient) == 1)
         {
            wordsArray.push(TEN_TO_TWELVE[uint(remainder)]);
            return;
         }
         
         //Si el cociente es 2 devuelve veintidós, veintitrés, ... (el caso de 21 ya se ha tratado más arriba)
         if (uint(quotient) == 2)
         {
            wordsArray.push(TWELVE_TO_THIRTY[uint(remainder)]);
            return;
         }
         
         //En el resto de los casos:
         wordsArray.push(TENS[uint(quotient)]);
         wordsArray.push("y");
         solveNaturalPart(remainder, gender);
      }
      private static function solveUnits(inStr:String, gender:String):void
      {
         var returnedStr:String = UNITS[uint(inStr)];
         if (uint(inStr) == 1) returnedStr += getGenderSuffix(gender);
         wordsArray.push(returnedStr);
      }
      private static function getGenderSuffix(gender:String):String
      {
         if (gender == NumberToWords.GENDER_FEMALE) return "a";
         if (gender == NumberToWords.GENDER_MALE) return "o";
         return "";
      }
   }
}

¿Sabes SQL? ¿No-SQL? Aprende MySQL, PostgreSQL, MongoDB, Redis y más con el Curso Profesional de Bases de Datos que empieza el martes, en vivo.

Publica tu comentario

o puedes...

¿Estás registrado en Cristalab y quieres
publicar tu URL y avatar?

¿No estás registrado aún pero quieres hacerlo antes de publicar tu comentario?

Registrate