CifrasEnLetras.cs

  1. // CifrasEnLetras.cs
  2.  
  3. using System;
  4. using System.Text; // StringBuilder
  5.  
  6. namespace ProInf.net
  7. {
  8.  
  9. /// <summary>
  10. /// CifrasEnLetras sirve para expresar una serie de cifras en letras.
  11. /// A modo de ejemplo convierte <q>22</q> en <q>veintidós</q>.
  12. /// Puede convertir un número entre una y ciento veintiséis cifras como máximo.
  13. /// </summary>
  14. /// <dl>
  15. /// <dt>Ejemplos de uso:</dt>
  16. /// <dd><code>CifrasEnLetras.convertirEurosEnLetras(22.34)</code> &rarr; <samp>"veintidós euros con treinta y cuatro céntimos"</samp></dd>
  17. /// <dd><code>CifrasEnLetras.convertirNumeroEnLetras("35,67")</code> &rarr; <samp>"treinta y cinco con sesenta y siete"</samp></dd>
  18. ///
  19. /// <dt>Enlaces de referencia:</dt>
  20. /// <dd><a href="http://es.wikipedia.org/wiki/Anexo:Lista_de_n%C3%BAmeros">Lista de números en la Wikipedia</a></dd>
  21. /// <dd><a href="http://es.encarta.msn.com/encyclopedia_761577100/Signos_matem%C3%A1ticos.html">Signos matemáticos en Encarta</a></dd>
  22. /// <dd><a href="http://es.wikipedia.org/wiki/Nombres_de_los_n%C3%BAmeros_en_espa%C3%B1ol">Nombres de los números en español</a></dd>
  23. ///
  24. /// <dt>Tareas pendientes:</dt>
  25. /// <dd>Función ConvertirAñosEnLetras: "cuatro años", "un lustro", "una década", "dos décadas", "un siglo", "un milenio"</dd>
  26. /// <dd>Función ConvertirOrdinalesEnLetras: "primero", "segundo", etc.</dd>
  27. /// <dd>Función ConvertirCifrasEnRomano y convertirRomanoEnCifras</dd>
  28. /// <dd>Función ConvertirFechasEnLetras: "21-XI-2007" &rarr; "veintiuno de noviembre de dos mil siete"</dd>
  29. ///
  30. /// <dt>Licencia:</dt>
  31. /// <dd><a href="http://creativecommons.org/licenses/GPL/2.0/deed.es">
  32. /// Este software está sujeto a la CC-GNU GPL</a>
  33. /// </dd>
  34. /// </dl>
  35. ///
  36. /// @author Francisco Cascales <fco@proinf.net>
  37. /// @version 0.01, 8-dic-2007 - Inicio del proyecto
  38. /// @version 0.02, 12-dic-2007 - Cifras en femenino
  39. /// @version 0.03, 17-dic-2007 - Formatear cifras separándolas en grupos
  40. /// @version 0.04, 22-dic-2007 - Múltiplos de millón con preposición "de" antes del concepto:
  41. /// "un millón de euros", "dos millones de euros", "un millón mil un euros"
  42. /// Las cifras superiores al millón siempre en masculino.
  43. /// "doscientos millones doscientas mil personas"
  44. /// @version 0.05, 7-ene-2008 - Mejoras estructurales
  45. /// @versión 0.06 19-ene-2011 - Convertido a C# con MonoDevelop 2.4
  46. ///
  47. public static class CifrasEnLetras
  48. {
  49.  
  50. //------------------------------------------------------------
  51. // CONSTANTES
  52.  
  53. private const string PREFIJO_ERROR = "Error: ";
  54. private const string COMA = ",";
  55. private const string MENOS = "-";
  56.  
  57. //------------------------------------------------------------
  58. // ENUMERACIONES
  59.  
  60. public enum Genero {
  61. neutro, masculino, femenino
  62. };
  63.  
  64. public static Genero generoDesdeNumero(int numero) { if (numero==0) return Genero.neutro; else if (numero==1) return Genero.masculino; return Genero.femenino; }
  65.  
  66. //------------------------------------------------------------
  67. // LISTAS
  68.  
  69. // Letras de los números entre el 0 y el 29
  70. private static string[] listaUnidades = {
  71. "cero", "un", "dos", "tres", "cuatro", "cinco", "seis", "siete", "ocho", "nueve",
  72. "diez", "once", "doce", "trece", "catorce", "quince", "dieciséis", "diecisiete", "dieciocho", "diecinueve",
  73. "veinte", "veintiún", "veintidós", "veintitrés", "veinticuatro", "veinticinco", "veintiséis", "veintisiete", "veintiocho", "veintinueve"
  74. };
  75. // Letras de las decenas
  76. private static string[] listaDecenas = {
  77. "", "diez", "veinte", "treinta", "cuarenta", "cincuenta", "sesenta", "setenta", "ochenta", "noventa"
  78. };
  79. // Letras de las centenas
  80. private static string[] listaCentenas = {
  81. "", "cien", "doscientos", "trescientos", "cuatrocientos", "quinientos", "seiscientos", "setecientos", "ochocientos", "novecientos"
  82. };
  83. // Letras en singular de los órdenes de millón.
  84. private static string[] listaOrdenesMillonSingular = {
  85. "", "millón", "billón", "trillón", "cuatrillón", "quintillón",
  86. "sextillón", "septillón", "octillón", "nonillón", "decillón",
  87. "undecillón", "duodecillón", "tridecillón", "cuatridecillón", "quidecillón",
  88. "sexdecillón", "septidecillón", "octodecillón", "nonidecillón", "vigillón"
  89. };
  90. // Letras en plural de los órdenes de millón
  91. private static string[] listaOrdenesMillonPlural = {
  92. "", "millones", "billones", "trillones", "cuatrillones", "quintillones",
  93. "sextillones", "septillones", "octillones", "nonillones", "decillones",
  94. "undecillones", "duodecillones", "tridecillones", "cuatridecillones", "quidecillones",
  95. "sexdecillones", "septidecillones", "octodecillones", "nonidecillones", "vigillones"
  96. };
  97.  
  98. /*-----
  99. // ORDINALES (Wikipedia: "Nombres de los números en español", "Número ordinal")
  100.  
  101. // Letras de los ordinales entre 0º y 19º
  102. private static string[] listaUnidadesOrdinales = {
  103. "ningún", "primer", "segundo", "tercer", "cuarto", "quinto", "sexto", "séptimo", "octavo", "noveno",
  104. "décimo", "undécimo", "duodécimo", "decimotercer", "decimocuarto", "decimoquinto", "decimosexto", "decimoséptimo", "decimoctavo", "decimonoveno"
  105. };
  106. // Letras de las decenas ordinales
  107. private static string[] listaDecenasOrdinales = {
  108. "", "décimo", "vigésimo", "trigésimo", "cuadragésimo", "quincuagésimo", "sexagésimo", "septuagésimo", "octogésimo", "nonagésimo"
  109. };
  110. // Letras de las centenas ordinales
  111. private static string[] listaCentenasOrdinales = {
  112. "", "centésimo", "ducentésimo", "tricentésimo", "cuadringentésimo", "quingentésimo", "sexcentésimo", "septingentésimo", "octingentésimo", "noningentésimo"
  113. };
  114. // Letras de las potencias de diez ordinales
  115. private static string[] listaPotenciasDiezOrdinales = {
  116. "", "décimo", "centésimo", "milésimo", "diezmilésimo", "cienmilésimo", "millonésimo"
  117. };
  118. -----*/
  119.  
  120. //------------------------------------------------------------
  121. // MÉTODOS PRINCIPALES
  122.  
  123. /// Convierte a letras los números entre 0 y 29.
  124. /// Ejemplo: <code>convertirUnidades(21,Genero.femenino)</code> &rarr; <samp>"veintiuna"</samp>
  125. ///
  126. public static string convertirUnidades (int unidades, Genero genero) {
  127. if (unidades == 1) {
  128. if (genero == Genero.masculino) return "uno";
  129. else if (genero == Genero.femenino) return "una";
  130. }
  131. else if (unidades == 21) {
  132. if (genero == Genero.masculino) return "veintiuno";
  133. else if (genero == Genero.femenino) return "veintiuna";
  134. }
  135. return listaUnidades[unidades];
  136. }
  137.  
  138. /// Convierte a letras las centenas
  139. /// Ejemplo: <code>convertirCentenas(2,Genero.femenino)</code> &rarr; <samp>"doscientas"</samp>
  140. ///
  141. public static string convertirCentenas (int centenas, Genero genero) {
  142. string resultado = listaCentenas[centenas];
  143. if (genero == Genero.femenino) resultado = resultado.Replace("iento","ienta");
  144. return resultado;
  145. }
  146.  
  147. /// Primer centenar: del cero al noventa y nueve.
  148. /// <dl>
  149. /// <dt>Ejemplos:</dt>
  150. /// <dd><code>convertirDosCifras(22,Genero.neutro)</code> &rarr; <samp>"veintidós"</samp></dd>
  151. /// </dl>
  152. /// <see cref="convertirUnidades(int,Genero)"/>
  153. ///
  154. public static string convertirDosCifras(int cifras, Genero genero) {
  155. int unidad = cifras % 10;
  156. int decena = cifras / 10;
  157. if (cifras < 30) return convertirUnidades(cifras, genero);
  158. else if (unidad == 0) return listaDecenas[decena];
  159. else return listaDecenas[decena] + " y " + convertirUnidades(unidad, genero);
  160. }
  161.  
  162. /// Primer millar: del cero al novecientos noventa y nueve.
  163. /// <dl>
  164. /// <dt>Ejemplos:</dt>
  165. /// <dd><code>convertirTresCifras(222,Genero.neutro)</code> &rarr; <samp>"doscientos veintidós"</samp></dd>
  166. /// </dl>
  167. /// <see cref="convertirDosCifras(int,Genero)"/>
  168. /// <see cref="convertirCentenas(int,Genero)"/>
  169. ///
  170. public static string convertirTresCifras(int cifras, Genero genero) {
  171. int decenas_y_unidades = cifras % 100;
  172. int centenas = cifras / 100;
  173. if (cifras < 100) return convertirDosCifras(cifras, genero);
  174. else if (decenas_y_unidades == 0) return convertirCentenas(centenas, genero);
  175. else if (centenas == 1) return "ciento " + convertirDosCifras(decenas_y_unidades, genero);
  176. else return convertirCentenas(centenas, genero) + " " + convertirDosCifras(decenas_y_unidades, genero);
  177. }
  178.  
  179. /// Primer millón: del cero al novecientos noventa y nueve mil novecientos noventa y nueve.
  180. /// <dl>
  181. /// <dt>Ejemplos:</dt>
  182. /// <dd><code>convertirSeisCifras(222222)</code> &rarr; <samp>"doscientos veintidós mil doscientos veintidós"</samp></dd>
  183. /// </dl>
  184. /// <see cref="convertirTresCifras(int,Genero)"/>
  185. ///
  186. public static string convertirSeisCifras(int cifras, Genero genero) {
  187. int primerMillar = cifras % 1000;
  188. int grupoMiles = cifras / 1000;
  189. Genero generoMiles = genero == Genero.masculino ? Genero.neutro : genero;
  190. if (grupoMiles == 0) return convertirTresCifras(primerMillar, genero);
  191. else if (grupoMiles == 1) {
  192. if (primerMillar == 0) return "mil";
  193. else return "mil " + convertirTresCifras(primerMillar, genero);
  194. }
  195. else if (primerMillar == 0) return convertirTresCifras(grupoMiles, generoMiles) + " mil";
  196. else return convertirTresCifras(grupoMiles, generoMiles) + " mil " + convertirTresCifras(primerMillar, genero);
  197. }
  198.  
  199. /// <summary>
  200. /// Números enteros entre el cero y el novecientos noventa y nueve mil novecientos noventa y nueve vigillones... etc, etc.<br />
  201. /// Es decir entre el 0 y el (10<sup>126</sup>)-1 o bien números entre 1 y 126 cifras.<br />
  202. /// Las cifras por debajo del millón pueden ir en masculino o en femenino.
  203. /// </summary>
  204. ///<dl>
  205. ///<dt>Ejemplos:</dt>
  206. ///<dd><code>convertirCifrasEnLetras("22222222")</code> &rarr; <samp>"veintidós millones doscientos veintidós mil doscientos veintidós"</samp></dd>
  207. /// <dd><code>convertirCifrasEnLetras("")</code> &rarr; <samp>"No hay ningún número"</samp></dd>
  208. /// <dd><code>convertirCifrasEnLetras(repetirCaracter('9',127))</code> &rarr; <samp>"El número es demasiado grande ya que tiene más de 126 cifras"</samp></dd>
  209. /// <dd><code>convertirCifrasEnLetras("0x")</code> &rarr; <samp>"Uno de los caracteres no es una cifra decimal"</samp></dd>
  210. /// <dd><code>convertirCifrasEnLetras(repetirCaracter('9',126))</code> &rarr; <samp>"novecientos noventa y nueve mil novecientos noventa y nueve vigillones..."</samp></dd>
  211. /// <dd><code>convertirCifrasEnLetras(10^6)</code> &rarr; <samp>"un millón"</samp></dd>
  212. /// <dd><code>convertirCifrasEnLetras(10^12)</code> &rarr; <samp>"un billón"</samp></dd>
  213. /// <dd><code>convertirCifrasEnLetras(10200050)</code> &rarr; <samp>"diez millones doscientos mil cincuenta"</samp></dd>
  214. /// <dd><code>convertirCifrasEnLetras(10001000)</code> &rarr; <samp>"diez millones mil"</samp></dd>
  215. /// <dd><code>convertirCifrasEnLetras("1" + repetirCaracter('0',120))</code> &rarr; <samp>"un vigillón"</samp></dd>
  216. /// <dd><code>convertirCifrasEnLetras("2" + repetirCaracter('0',18))</code> &rarr; <samp>"dos trillones"</samp></dd>
  217. /// <dd><code>convertirCifrasEnLetras("4792347927489", "\n")</code> &rarr; <samp>"..."</samp></dd>
  218. /// <dd><code>convertirCifrasEnLetrasFemeninas("501")</code> &rarr; <samp>"quinientas una"</samp></dd>
  219. /// <dd><code>convertirCifrasEnLetrasFemeninas("240021")</code> &rarr; <samp>"doscientas cuarenta mil veintiuna"</samp></dd>
  220. /// </dl>
  221. /// <see cref="convertirSeisCifras(int,Genero)"/>
  222. ///
  223. public static string convertirCifrasEnLetras(string cifras, Genero genero,
  224. string separadorGruposSeisCifras)
  225. {
  226. // Inicialización
  227. cifras = cifras.Trim();
  228. int numeroCifras = cifras.Length;
  229.  
  230. // Comprobación
  231. if (numeroCifras == 0) return PREFIJO_ERROR + "No hay ningún número";
  232. for (int indiceCifra=0; indiceCifra<numeroCifras; ++indiceCifra) {
  233. char cifra = cifras[indiceCifra];
  234. bool esDecimal = "0123456789".IndexOf(cifra) >= 0;
  235. if (!esDecimal) return PREFIJO_ERROR + "Uno de los caracteres no es una cifra decimal";
  236. }
  237. if (numeroCifras > 126) return PREFIJO_ERROR + "El número es demasiado grande ya que tiene más de 126 cifras";
  238.  
  239. // Preparación
  240. int numeroGruposSeisCifras = numeroCifras / 6 + Math.Sign(numeroCifras);
  241. string cerosIzquierda = new string('0', numeroGruposSeisCifras * 6 - numeroCifras);
  242. cifras = cerosIzquierda + cifras;
  243. int ordenMillon = numeroGruposSeisCifras - 1;
  244.  
  245. // Procesamiento
  246. StringBuilder resultado = new StringBuilder();
  247. for (int indiceGrupo=0; indiceGrupo<numeroGruposSeisCifras*6; indiceGrupo+=6) {
  248. int seisCifras = int.Parse( cifras.Substring(indiceGrupo, 6) );
  249. if (seisCifras != 0) {
  250. if (resultado.Length > 0) resultado.Append(separadorGruposSeisCifras);
  251.  
  252. if (ordenMillon == 0) {
  253. resultado.Append(convertirSeisCifras(seisCifras, genero));
  254. }
  255. else if (seisCifras == 1) {
  256. resultado.Append("un " + listaOrdenesMillonSingular[ordenMillon]);
  257. }
  258. else {
  259. resultado.Append(convertirSeisCifras(seisCifras, Genero.neutro) +
  260. " " + listaOrdenesMillonPlural[ordenMillon]);
  261. }
  262. }
  263. ordenMillon--;
  264. }
  265.  
  266. // Finalización
  267. if (resultado.Length == 0) resultado.Append(listaUnidades[0]);
  268. return resultado.ToString();
  269. }
  270. /// <see cref="convertirCifrasEnLetras(string, Genero, string)"/>
  271. public static string convertirCifrasEnLetras(string cifras) {
  272. return convertirCifrasEnLetras(cifras, Genero.neutro, " ");
  273. }
  274. /// <see cref="convertirCifrasEnLetras(string, Genero, string)"/>
  275. public static string convertirCifrasEnLetrasMasculinas(string cifras) {
  276. return convertirCifrasEnLetras(cifras, Genero.masculino, " ");
  277. }
  278. /// <see cref="convertirCifrasEnLetras(string, Genero, string)"/>
  279. public static string convertirCifrasEnLetrasFemeninas(string cifras) {
  280. return convertirCifrasEnLetras(cifras, Genero.femenino, " ");
  281. }
  282.  
  283. /// Expresa un número con decimales y signo en letras
  284. /// acompañado del tipo de medida para la parte entera y la parte decimal.
  285. /// <ul>
  286. /// <li>Los caracteres no numéricos son ignorados.</li>
  287. /// <li>Los múltiplos de millón tienen la preposición <q>de</q> antes de la palabra.</li>
  288. /// <li>El género masculino o femenino sólo puede influir en las cifras inferiores al millón</li>
  289. /// </ul>
  290. /// <dl><dt>Ejemplos:</dt>
  291. /// <dd><code>convertirNumeroEnLetras("-123,45",2)</code> &rarr; <samp>"menos ciento veintitrés con cuarenta y cinco"</samp></dd>
  292. /// <dd><code>convertirNumeroEnLetras("2.000,25", 3, "kilo","gramo")</code> &rarr; <samp>"dos mil kilos con doscientos cincuenta gramos"</samp></dd>
  293. /// <dd><code>convertirNumeroEnLetras("43,005", 3, "kilómetro","metro")</code> &rarr; <samp>"cuarenta y tres kilómetros con cinco metros"</samp></dd>
  294. /// <dd><code>convertirNumeroEnLetras("1.270,23", 2, "euro","céntimo")</code> &rarr; <samp>"mil doscientos setenta euros con veintitrés céntimos"</samp></dd>
  295. /// <dd><code>convertirNumeroEnLetras("1", 2, "euro","céntimo")</code> &rarr; <samp>"un euro con cero céntimos"</samp></dd>
  296. /// <dd><code>convertirNumeroEnLetras("0,678", 2, "euro","céntimo")</code> &rarr; <samp>"cero euros con sesenta y siete céntimos"</samp></dd>
  297. /// <dd><code>convertirNumeroEnLetras("22.000,55", 0, "euro","")</code> &rarr; <samp>"veintidós mil euros"</samp></dd>
  298. /// <dd><code>convertirNumeroEnLetras("-,889")</code> &rarr; <samp>"menos cero con ochocientos ochenta y nueve"</samp></dd>
  299. /// <dd><code>convertirNumeroEnLetras("200",0,"manzana",true)</code> &rarr; <samp>"doscientas manzanas"</samp></dd>
  300. /// <dd><code>convertirNumeroEnLetras("1,5",2,"peseta","céntimo",true,false)</code> &rarr; <samp>"una peseta con cincuenta céntimos"</samp></dd>
  301. /// <dd><code>convertirNumeroEnLetras("300,56",3,"segundo","milésima",false,true)</code> &rarr; <samp>"trescientos segundos con quinientas sesenta milésimas"</samp></dd>
  302. /// <dd><code>convertirNumeroEnLetras("21,21",2,"niño","niña",false,true)</code> &rarr; <samp>"veintiún niños con veintiuna niñas"</samp></dd>
  303. /// <dd><code>convertirNumeroEnLetras("1000000",,"euro")</code> &rarr; <samp>"un millón de euros"</samp></dd>
  304. /// <dd><code>convertirNumeroEnLetras("200.200.200","persona",true)</code> &rarr; <samp>"doscientos millones doscientas mil doscientas personas"</samp></dd>
  305. /// <dd><code>convertirNumeroEnLetras("221.221.221")</code> &rarr; <samp>"doscientos veintiún millones doscientos veintiún mil doscientos veintiuno"</samp></dd>
  306. /// </dl>
  307. /// @param numeroDecimales Si es -1 el número de decimales es automático
  308. /// <see cref="convertirCifrasEnLetras(string, Genero, string)"/>
  309. /// <see cref="procesarEnLetras(string, string, string, bool)"/>
  310. ///
  311. public static string convertirNumeroEnLetras(string cifras, int numeroDecimales,
  312. string palabraEnteraSingular, string palabraEnteraPlural, bool esFemeninaPalabraEntera,
  313. string palabraDecimalSingular, string palabraDecimalPlural, bool esFemeninaPalabraDecimal)
  314. {
  315. // Limpieza
  316. cifras = dejarSoloCaracteresDeseados(cifras, "0123456789" + COMA + MENOS);
  317.  
  318. // Comprobaciones
  319. int repeticionesMenos = numeroRepeticiones(cifras, MENOS);
  320. int repeticionesComa = numeroRepeticiones(cifras, COMA);
  321. if (repeticionesMenos > 1 || (repeticionesMenos == 1 && !cifras.StartsWith(MENOS)) )
  322. return PREFIJO_ERROR + "Símbolo negativo incorrecto o demasiados símbolos negativos";
  323. else if (repeticionesComa > 1) return PREFIJO_ERROR + "Demasiadas comas decimales";
  324.  
  325. // Negatividad
  326. bool esNegativo = cifras.StartsWith(MENOS);
  327. if (esNegativo) cifras = cifras.Substring(1);
  328.  
  329. // Preparación
  330. int posicionComa = cifras.IndexOf(COMA);
  331. if (posicionComa == -1) posicionComa = cifras.Length;
  332.  
  333. string cifrasEntera = cifras.Substring(0, posicionComa);
  334. if (cifrasEntera.Equals("") || cifrasEntera.Equals(MENOS)) cifrasEntera = "0";
  335. string cifrasDecimal = cifras.Substring(Math.Min(posicionComa + 1, cifras.Length));
  336.  
  337. bool esAutomaticoNumeroDecimales = numeroDecimales < 0;
  338. if (esAutomaticoNumeroDecimales) {
  339. numeroDecimales = cifrasDecimal.Length;
  340. }
  341. else {
  342. cifrasDecimal = cifrasDecimal.Substring(0, Math.Min(numeroDecimales, cifrasDecimal.Length));
  343. string cerosDerecha = new string('0', numeroDecimales - cifrasDecimal.Length);
  344. cifrasDecimal = cifrasDecimal + cerosDerecha;
  345. }
  346.  
  347. // Cero
  348. bool esCero = dejarSoloCaracteresDeseados(cifrasEntera,"123456789").Equals("") &&
  349. dejarSoloCaracteresDeseados(cifrasDecimal,"123456789").Equals("");
  350.  
  351. // Procesar
  352. StringBuilder resultado = new StringBuilder();
  353.  
  354. if (esNegativo && !esCero) resultado.Append("menos ");
  355.  
  356. string parteEntera = procesarEnLetras(cifrasEntera, palabraEnteraSingular, palabraEnteraPlural, esFemeninaPalabraEntera);
  357. if (parteEntera.StartsWith(PREFIJO_ERROR)) return parteEntera;
  358. resultado.Append(parteEntera);
  359.  
  360. if (!cifrasDecimal.Equals("")) {
  361. string parteDecimal = procesarEnLetras(cifrasDecimal, palabraDecimalSingular, palabraDecimalPlural, esFemeninaPalabraDecimal);
  362. if (parteDecimal.StartsWith(PREFIJO_ERROR)) return parteDecimal;
  363. resultado.Append(" con ");
  364. resultado.Append(parteDecimal);
  365. }
  366.  
  367. return resultado.ToString();
  368. }
  369. /// @see #convertirNumeroEnLetras(string, int, string, string, bool, string, string, bool)
  370. public static string convertirNumeroEnLetras(string cifras) {
  371. return convertirNumeroEnLetras(cifras, -1, "","",false,"","",false);
  372. }
  373. /// @see #convertirNumeroEnLetras(string, int, string, string, bool, string, string, bool)
  374. public static string convertirNumeroEnLetras(string cifras, int numeroDecimales) {
  375. return convertirNumeroEnLetras(cifras, numeroDecimales, "","",false,"","",false);
  376. }
  377. /// @see #convertirNumeroEnLetras(string, int, string, string, bool, string, string, bool)
  378. public static string convertirNumeroEnLetras(string cifras, string palabraEntera) {
  379. return convertirNumeroEnLetras(cifras, 0, palabraEntera, palabraEntera+"s", false,"","",false);
  380. }
  381. /// @see #convertirNumeroEnLetras(string, int, string, string, bool, string, string, bool)
  382. public static string convertirNumeroEnLetras(string cifras, string palabraEntera, bool esFemeninaPalabraEntera) {
  383. return convertirNumeroEnLetras(cifras, 0, palabraEntera, palabraEntera+"s", esFemeninaPalabraEntera,"","",false);
  384. }
  385. /// @see #convertirNumeroEnLetras(string, int, string, string, bool, string, string, bool)
  386. public static string convertirNumeroEnLetras(string cifras, int numeroDecimales, string palabraEntera, string palabraDecimal) {
  387. return convertirNumeroEnLetras(cifras, numeroDecimales,
  388. palabraEntera, palabraEntera+"s", false,
  389. palabraDecimal, palabraDecimal+"s",false);
  390. }
  391. /// @see #convertirNumeroEnLetras(string, int, string, string, bool, string, string, bool)
  392. public static string convertirNumeroEnLetras(string cifras, int numeroDecimales,
  393. string palabraEntera, string palabraDecimal, bool esFemeninaPalabraEntera, bool esFemeninaPalabraDecimal)
  394. {
  395. return convertirNumeroEnLetras(cifras, numeroDecimales,
  396. palabraEntera, palabraEntera+"s", esFemeninaPalabraEntera,
  397. palabraDecimal, palabraDecimal+"s",esFemeninaPalabraDecimal);
  398. }
  399.  
  400. /// Función auxiliar de <code>convertirNumeroEnLetras</code>
  401. /// para procesar por separado la parte entera y la parte decimal
  402. /// <see cref="convertirCifrasEnLetras(string, bool, string)"/>
  403. ///
  404. private static string procesarEnLetras(string cifras,
  405. string palabraSingular, string palabraPlural, bool esFemenina)
  406. {
  407. // Género
  408. Genero genero = Genero.neutro;
  409. if (esFemenina) genero = Genero.femenino;
  410. else if (palabraSingular.Equals("")) genero = Genero.masculino;
  411.  
  412. // Letras
  413. string letras = convertirCifrasEnLetras(cifras, genero, " ");
  414. if (letras.StartsWith(PREFIJO_ERROR)) return letras;
  415.  
  416. // Propiedades // 7-ene-2008
  417. bool esCero = letras.Equals(convertirUnidades(0, genero)) || letras.Equals(""); //---letras.Equals("cero") || letras.Equals("");
  418. bool esUno = letras.Equals(convertirUnidades(1, genero)); //---letras.Equals("un") || letras.Equals("una") || letras.Equals("uno");
  419. bool esMultiploMillon = !esCero && cifras.EndsWith("000000");
  420.  
  421. // Palabra
  422. string palabra = "";
  423. if (!palabraSingular.Equals("")) {
  424. if (esUno || palabraPlural.Equals(""))
  425. palabra = palabraSingular;
  426. else
  427. palabra = palabraPlural;
  428. }
  429.  
  430. // Resultado
  431. StringBuilder resultado = new StringBuilder();
  432. resultado.Append(letras);
  433. if (!palabra.Equals("")) {
  434. if (esMultiploMillon) resultado.Append (" de ");
  435. else resultado.Append(" ");
  436. resultado.Append(palabra);
  437. }
  438. return resultado.ToString();
  439. }
  440.  
  441. /// Convertir euros en letras
  442. /// <dl>
  443. /// <dt>Ejemplos:</dt>
  444. /// <dd><code>convertirEurosEnLetras("44276598801,2",2)</code> &rarr; <samp>"cuatrocientos noventa y ocho mil un euros con veinte céntimos"</samp></dd>
  445. /// <dd><code>convertirEurosEnLetras(85009)</code> &rarr; <samp>"ochenta y cinco mil nueve euros"</samp></dd>
  446. /// <dd><code>convertirEurosEnLetras(10200.35)</code> &rarr; <samp>"diez mil doscientos euros con treinta y cinco céntimos"</samp></dd>
  447. /// </dl>
  448. /// <see cref="convertirNumeroEnLetras(string, int, string, string)"/>
  449. ///
  450. public static string convertirEurosEnLetras(string cifras, int numeroDecimales) {
  451. return convertirNumeroEnLetras(cifras, numeroDecimales, "euro", "céntimo");
  452. }
  453. /// <see cref="convertirEurosEnLetras(string, int)"/>
  454. public static string convertirEurosEnLetras(long euros) {
  455. string cifras = euros.ToString();
  456. return convertirEurosEnLetras(cifras, 0);
  457. }
  458. /// <see cref="convertirEurosEnLetras(string, int)"/>
  459. public static string convertirEurosEnLetras(double euros) {
  460. string cifras = euros.ToString().Replace('.', ',');
  461. return convertirEurosEnLetras(cifras, 2);
  462. }
  463.  
  464. /// <dl>
  465. /// <dt>Ejemplos:</dt>
  466. /// <dd><code>11</code> &rarr; <samp>"undécimo"</samp></dd>
  467. /// <dd><code>2222</code> &rarr; <samp>"dosmilésimo ducentésimo vigésimo segundo"</samp></dd>
  468. /// </dl>
  469. ///
  470. public static string convertirOrdinalesEnLetras(string cifras, Genero genero) {
  471. return "";
  472. }
  473.  
  474. /// Convertir años en letras.
  475. /// Ejemplos: <samp>"cuatro años", "un lustro", "una década", "dos décadas", "un siglo", "un milenio"</samp>
  476. ///
  477. public static string convertirAñosEnLetras(string cifras) {
  478. return "";
  479. }
  480.  
  481. /// Convertir fechas en letras.
  482. /// <dl>
  483. /// <dt>Ejemplos:</dt>
  484. /// <dd>"21-XI-2007" &rarr; "veintiuno de noviembre de dos mil siete"</dd>
  485. /// </dl>
  486. ///
  487. public static string convertirFechasEnLetras(string fecha) {
  488. return "";
  489. }
  490.  
  491. //------------------------------------------------------------
  492. // FUNCIONES AUXILIARES
  493.  
  494. /// Borra todos los caracteres del texto que no sea alguno de los caracteres deseados.
  495. /// <dl>
  496. /// <dt>Ejemplos:</dt>
  497. /// <dd><code>dejarSoloCaracteresDeseados("89.500.400","0123456789")</code> &rarr; <samp>"89500400"</samp></dd>
  498. /// <dd><code>dejarSoloCaracteresDeseados("ABC-000-123-X-456","0123456789")</code> &rarr; <samp>"000123456"</samp></dd>
  499. /// </dl>
  500. ///
  501. public static string dejarSoloCaracteresDeseados(string texto, string caracteresDeseados) {
  502. int indice = 0;
  503. StringBuilder resultado = new StringBuilder(texto);
  504. while (indice < resultado.Length) {
  505. char caracter = resultado[indice];
  506. if (caracteresDeseados.IndexOf(caracter) < 0) resultado.Remove(indice, 1);
  507. else indice++;
  508. }
  509. return resultado.ToString();
  510. }
  511.  
  512. /// Cuenta el número de repeticiones en el texto de los caracteres indicados
  513. /// <dl>
  514. /// <dt>Ejemplos:</dt>
  515. /// <dd><code>numeroRepeticiones("89.500.400","0")</code> &rarr; <samp>4</samp></dd>
  516. /// </dl>
  517. ///
  518. public static int numeroRepeticiones(string texto, string caracteres) {
  519. int resultado = 0;
  520. for (int indice=0; indice<texto.Length; ++indice) {
  521. char caracter = texto[indice];
  522. if (caracteres.IndexOf(caracter) >= 0) resultado++;
  523. }
  524. return resultado;
  525. }
  526.  
  527. /// Separa las cifras en grupos de 6 con subrayados y los grupos de 6 en grupos de 2 con punto
  528. /// <dl>
  529. /// <dt>Ejemplos:</dt>
  530. /// <dd><code>formatearCifras("-4739249,2")</code> &rarr; <samp>"-4_739.249,2"</samp></dd>
  531. /// </dl>
  532. ///
  533. public static string formatearCifras(string cifras) {
  534. cifras = dejarSoloCaracteresDeseados(cifras, "0123456789" + COMA + MENOS);
  535. if (cifras.Length == 0) return cifras;
  536.  
  537. bool esNegativo = cifras.StartsWith(MENOS);
  538. if (esNegativo) cifras = cifras.Substring(1);
  539.  
  540. int posicionComa = cifras.IndexOf(COMA);
  541. bool esDecimal = posicionComa >= 0;
  542.  
  543. if (!esDecimal) posicionComa = cifras.Length;
  544. string cifrasEntera = cifras.Substring(0, posicionComa);
  545. string cifrasDecimal = "";
  546.  
  547. if (esDecimal) cifrasDecimal = cifras.Substring(Math.Min(posicionComa + 1, cifras.Length));
  548. if (cifrasEntera.Equals("")) cifrasEntera = "0";
  549.  
  550. StringBuilder resultado = new StringBuilder();
  551. int numeroCifras = cifrasEntera.Length;
  552. //int numeroGruposTresCifras = numeroCifras / 3 + Integer.signum(numeroCifras);
  553. bool par = true;
  554.  
  555. for (int indice=0; indice<numeroCifras; indice+=3) {
  556. int indiceGrupo = numeroCifras - indice;
  557. string tresCifras = cifras.Substring(Math.Max(indiceGrupo-3,0), indiceGrupo);
  558. if (indice > 0) {
  559. resultado.Insert(0, par==true?'.':'_');
  560. par = !par;
  561. }
  562. resultado.Insert(0, tresCifras);
  563. }
  564. if (esNegativo) resultado.Insert(0, MENOS);
  565. if (esDecimal) resultado.Append(COMA + cifrasDecimal);
  566.  
  567. return resultado.ToString();
  568. }
  569.  
  570. } // class CifrasEnLetras
  571.  
  572. } // namespace ProInf.net

Proinf.net