/* * [SpanishBase.java] * * Summary: Abstract Common code for Spanish and SpanishForCheques. * * Copyright: (c) 1999-2017 Roedy Green, Canadian Mind Products, http://mindprod.com * * Licence: This software may be copied and used freely for any purpose but military. * http://mindprod.com/contact/nonmil.html * * Requires: JDK 1.8+ * * Created with: JetBrains IntelliJ IDEA IDE http://www.jetbrains.com/idea/ * * Version History: * 1.1 2009-01-20 incorporate many changes suggested by Erwin Feldhaus */ package com.mindprod.inwords; import static java.lang.System.*; /** * Abstract Common code for Spanish and SpanishForCheques. * * @author Roedy Green, Canadian Mind Products * @version 1.1 2009-01-20 incorporate many changes suggested by Erwin Feldhaus * @since 1999 */ public abstract class SpanishBase implements ToWords { /** * word for one */ static final String ONE = "uno"; /** * word for one when combining */ static final String ONE_COMBINING = "un"; /** * word for 21 */ static final String TWENTY_ONE = "vientiuno"; /** * word for 21 when combining */ static final String TWENTY_ONE_COMBINING = "veinti�n"; /** * low nummbers 1 to 29 are irregular */ static final String[] lowName = { "", // 0 zero is shown as "" since it is never used in combined forms "uno", // 1 "dos", // 2 "tres", // 3 "cuatro", // 4 "cinco", // 5 "seis", // 6 "siete", // 7 "ocho", // 8 "nueve", // 9 "diez", // 10 "once", // 11 "doce", // 12 "trece", // 13 "catorce", // 14 "quince", // 15 "diecis�is", // 16 "diecisiete", // 17 "dieciocho", // 18 "diecinueve", // 19 "veinte", // 20 "veinti�n/vientiuno", // 21 "veintid�s", // 22 "veintitr�s", // 23 "veinticuatro", // 24 "veinticinco", // 25 "veintis�is", // 26 "veintisiete", // 27 "veintiocho", // 28 "veintinueve", // 29 }; /** * true if want additional debug output */ private static final boolean DEBUGGING = false; private static final int FIRST_COPYRIGHT_YEAR = 2003; /** * the word for and */ private static final String AND = "y"; /** * undisplayed copyright notice. * * @noinspection UnusedDeclaration */ private static final String EMBEDDED_COPYRIGHT = "Copyright: (c) 2003-2017 Roedy Green, Canadian Mind Products, http://mindprod.com"; /** * word for minus */ private static final String MINUS = "menos"; /** * Spansh for 100 when appears by itself */ private static final String PLAIN_100 = "cien"; /** * word for zero */ private static final String ZERO = "cero"; /** * names for major digit grouping, plural */ private static final String[] groupNamePlural = { "", // units 1 // 100s are irregular, so no word. "mil", // 1,000 10^3 "milliones", // 1,000,000 10^6 // millardo rarely used 1,000,000,000 10^9 "billones", // 1,000,000,000,000 10^12 "trillones", // 1,000,000,000,000,000,000 10^18 "cuatrillones", // 1,000,000,000,000,000,000,000,000 10^24 }; /** * names for major digit grouping, singluar. */ private static final String[] groupNameSingular = { /* * We only need up to a quintillion, since a long is about 9 * 10 ^ 18 */ "", // units 1 // 100s are irregular, so no word. "mil", // 1,000 10^3 "mill\u00f3n", // 1,000,000 10^6 // millardo rarely used 1,000,000,000 10^9 "bill\u00f3n", // 1,000,000,000,000 10^12 "trill\u00f3n", // 1,000,000,000,000,000,000 10^18 "cuatrill\u00f3n", // 1,000,000,000,000,000,000,000,000 10^24 }; /** * how to express various numbers of hundreds */ private static final String[] hundreds = { "", // 0 zero is shown as "" since it is never used in combined forms "ciento", // 100 singular 100 by itself is cien "doscientos", // 200 plural "trescientos", // 300 "cuatrocientos", // 400 "quinientos", // 500 "seiscientos", // 600 "setecientos", // 700 no �i� in sete) "ochocientos", // 800 "novecientos", // 900 }; /** * how to do the even powers of ten 0, 10, 20, 30 ... 90 */ private static final String[] tys = { "cero", // 0 "diez", // 10 "veinte", // 20 "treinta", // 30 "cuarenta", // 40 "cincuenta", // 50 "sesenta", // 60 "setenta", // 70 "ochenta", // 80 "noventa", // 90 }; /** * divisors to split numbere in named ranges. * HowToProcess many of this group is needed to form one of the succeeding group. */ private static final int[] divisor = { /* unit, [hundred] thousand, million, billion, trillion */ 1000, 1000, 1000000, 1000000, 1000000, }; /** * get value for number in range 0..29 * non-monetary version * * @param group 0= units 1=thousands etc. * @param i value 0..29 * * @return word for that value */ abstract String getLowName( int group, int i ); /** * get Spanish word for one * * @param group 0= units 1=thousands etc. * * @return Spanish word for one, possibly empty. */ abstract String wordForOne( int group ); /** * convert long integer into Spanish words. e.g. -12.345 -> menos doce mil trescientos cuarenta y cinco Handles * negative and positive integers. on range -Long.MAX_VALUE .. Long.MAX_VALUE; It cannot handle Long.MIN_VALUE; * * @param num number to convert to words * * @return words */ @SuppressWarnings( { "WeakerAccess" } ) public String toWords( long num ) { if ( DEBUGGING ) { out.println( " num:" + num ); } if ( num == 0 ) { return ZERO; } boolean negative = ( num < 0 ); if ( negative ) { num = -num; } // s is where we accumulate the Spanish, adding word on the left // as we work toward higher order digits. // We don't use a StringBuilder since they are designed to tack on the right. String s = ""; // Work least significant digit to most, right to left. // until high order part is all 0s. // Typically generate three digits each time through the loop. for ( int group = 0; num > 0; group++ ) { // remdr is 0 to 3 digits to process, working from night assert 0 <= group && group < divisor.length : group + " out of bounds"; int remdr = ( int ) ( num % divisor[ group ] ); // num now has digits to the left we will process later. num = num / divisor[ group ]; if ( DEBUGGING ) { out.println( "group:" + group + " remdr:" + remdr + " num:" + num + " s:" + s ); } if ( remdr == 0 ) { // handle 0 continue; } // the value of this group in words, without the units String t; if ( remdr == 1 ) { // handle 1 : uno, [cien], [un] mil, un mill�n, un bill�n, un trill�n t = wordForOne( group ); } else if ( remdr < 30 ) { // handle 2 ..29 t = getLowName( group, remdr ); } else if ( remdr < 100 ) { // handle 30 .. 99 int units = remdr % 10; int tens = remdr / 10; t = tys[ tens ]; switch ( units ) { case 0: /* multiple of 10 e.g. 40 cuarenta */ break; default: /* e.g. veinte y uno */ t += " " + AND + " " + getLowName( group, units ); break; } // end switch } else if ( remdr == 100 ) { // handle 100 t = PLAIN_100; // 100 by itself } else if ( remdr < 1000 ) { // handle 101 ...999 int rest = remdr % 100; int cent = remdr / 100; t = hundreds[ cent ]; // 100 ciento combining formr if ( rest != 0 ) { t += " " + toWords( rest ); } } else { // handle 1000 and up t = toWords( remdr ); } // glue newly created left words to what we have already s = t + ( t.length() != 0 ? " " : "" ) + ( remdr > 1 ? groupNamePlural[ group ] : groupNameSingular[ group ] ) + ( s.length() > 0 ? ( " " + s ) : "" ); } // end for s = s.trim(); if ( negative ) { s = MINUS + " " + s; } return s; } // end inWords }