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.
Por Zguillez el 07 de Diciembre de 2009
gracias por compartirla
Por M@U el 08 de Diciembre de 2009