Ευρώ Ολογράφως

Εψαχνα εδώ και λίγο διάστημα για μια έτοιμη υλοποίηση εμφάνισης ποσών σε ευρώ στην λεκτική τους αναπαράσταση. Είδα αρκετές υλοποιήσεις σε διάφορες γλώσσες (λέμε τώρα, VB κάτι, ήταν όλες, με κάποιες εξαιρέσεις που ήταν μεταφράσεις σε C# των αντίστοιχων VB) με την κάθε μία να έχει τα υπέρ και τα κατά, αναλόγως τις ανάγκες που υπήρχαν.

Αλλη υλοποίηση υποστηρίζει ποσά μέχρι 999.999€ άλλη υποστηρίζει μέχρι 2 δεκαδικά, άλλη υποστηρίζει μεγαλύτερα ποσά, άλλη αρνητικά ποσά. Το να είναι μια υλοποίηση μετάφραση σε άλλη γλώσσα δεν είναι κάτι το μεμπτό, απλώς μου φάνηκε αστείο που όλες οι υλοποιήσεις ήταν VB ή VB.NET, ή VBScript. Ούτε καν COBOL! (Καλά που την θυμήθηκα αυτή τώρα; 🙂 )

Αυτό που έψαχνα να βρώ είναι μια κομψή υλοποίηση σε κάποια γλώσσα που να μην μου είναι εντελώς άγνωστη ώστε να μπορώ να προσαρμόσω τον κώδικα στα γούστα μου. Τον κώδικα που μου άρεσε περισσότερο τον βρήκα σε μια vb.net υλοποίηση του panos_sniper που έχει αναρτήσει στο dotnetzone.gr. Θα προτιμούσα κάτι σε C ή C++ αλλά και η vb.net δεν είναι πρόβλημα. Μπορεί να τρέξει, να δοκιμαστεί ότι δουλεύει σωστά και αν όλα είναι εντάξει το μόνο που μένει είναι να χρησιμοποιηθεί.

Οι πρώτες λίγες δοκιμές με μικρά νούμερα δούλεψαν σωστά, οπότε ήρθε η ώρα για λίγο πιο απαιτητικά νούμερα όπως το 0,001€ ή το 1,999€. Οταν παίζεις με αριθμητικά ποσά το νούμερο παραμένει ως έχει, αλλά όταν παίζεις με ποσά ολογράφως αναγκαστικά θα περιοριστείς στην υποδιαίρεση που έχει το κάθε νόμισμα. Για δραχμές παλιότερα, 0 δεκαδικά (οι δεκάρες είναι πολλά χρόνια που είχαν καταργηθεί) και για ευρώ τα λεπτά – 2 δεκαδικά. Συνεπώς όταν ο 0,001 γίνει ολογράφως, θα στρογγυλοποιηθεί στο 0,00€ και στο 1,999 στο 2,00€. Εδώ άρχισαν να εμφανίζονται τα πρώτα προβλήματα αφού έδινε αποτέλεσμα το μεν “ΚΑΙ ΛΕΠΤΑ” και το δε “ΕΝΑ ΕΥΡΩ ΚΑΙ ΕΚΑΤΟ ΛΕΠΤΑ”. Δεν είναι εντελώς λάθος το δεύτερο αλλά το σωστό είναι να γίνει “ΔΥΟ ΕΥΡΩ”.

Οι επόμενες δοκιμές αφορούσαν μεγαλύτερα νούμερα, όπως το 1.101.101,10 του αξέχαστου Χόρν στο “Μιά ζωή την έχουμε”. Αλλη μια διόρθωση που έπρεπε να γίνει. Στα μεγαλύτερα ποσά το αποτέλεσμα έδειξε ότι τα πήγε περίφημα, αλλά… …δεν έπαιζε τίμια. Το ΔΙΣεκατομμύριο/α αναφερόταν ως “ΔΙΣ” οπότε νούμερα όπως τα 1.235.000.000.000,00€ αναφερόταν ως “ΕΝΑ ΤΡΙΣ ΔΙΑΚΟΣΙΑ ΤΡΙΑΝΤΑ ΠΕΝΤΕ ΔΙΣ ΕΥΡΩ”. Αυτό ήταν οφθαλμοφανές ότι σήκωνε βελτίωση ώστε να είναι και γραμματικά ορθό. Το 1 ΔΙΣ να γίνει 1 ΔΙΣΕΚΑΤΟΜΜΥΡΙΟ, τα 2 ΔΙΣ να γίνουν 2 ΔΙΣΕΚΑΤΟΜΜΥΡΙΑ, κ.ο.κ.

Επιπλέον όταν το ποσό ήταν 0€ δεν εμφάνιζε τίποτε. Μου φάνηκε καλή ιδέα να μπορείς να επιλέξεις αν δεν θα εμφανίζει τίποτα ή θα λέει “ΜΗΔΕΝ ΕΥΡΩ”, όπως και το να προστεθούν αρνητικά ποσά: -1€ “ΜΕΙΟΝ ΕΝΑ ΕΥΡΩ”, και γιατί όχι να μπορείς να επιλέξεις αν θα εμφανίζει τη νομισματική μονάδα (Ευρώ, Λεπτά) ή όχι. Η VB δεν είναι και η αγαπημένη μου γλώσσα, προτιμώ να γράφω C++, αλλά για να μπορέσω να επικεντρωθώ γρηγορότερα στις διορθώσεις που ήθελα, είπα να κάνω με στάση σε C#. Ξεκίνησα τα global replaces και μετά αλλαγές με το χέρι ώστε να γίνει ο κώδικας C#. Το πρώτο πράγμα που πρέπει να προσέξεις όταν αλλάζεις κάποιον ξένο κώδικα, είναι αν δεν μπορείς να τον κάνεις καλύτερο, τουλάχιστον να μην τον κάνεις χειρότερο. Οπότε αφού C# και VB.NET χρησιμοποιούν το ίδιο framework, αν έχω κάνει κάποια χαζομάρα στη μετάφραση θα φανεί εύκολα. Πάνω σε αυτόν τον κώδικα έγιναν οι περισσότερες αλλαγές / διορθώσεις / επεκτάσεις / debugging.

Εχοντας φτάσει σε κάποιο ικανοποιητικό σημείο, ο κώδικας ήταν έτοιμος να δωθεί πίσω στη δημοσιότητα. (Βασικά να δωθεί σε υποψήφιους testers για να βγάλουν πιθανά λάθη και βελτιώσεις, αλλά αυτό δεν το λέμε!).

Οπότε, όποιος θέλει μπορεί να κατεβάσει τον κώδικα για μετατροπή σε ολογράφως σε C# από εδώ. ή απλώς να τον δεί παρακάτω.

public class Money
{
    private static string[] m   = { "", "ΕΝΑ ", "ΔΥΟ ", "ΤΡΙΑ ",
                                    "ΤΕΣΣΕΡΑ ", "ΠΕΝΤΕ ", "ΕΞΙ ",
                                    "ΕΠΤΑ ", "ΟΚΤΩ ", "ΕΝΝΕΑ " };
    private static string[] mF  = { "", "ΜΙΑ ", "", "ΤΡΕΙΣ ",
                                    "ΤΕΣΣΕΡΙΣ " };
    private static string[] d1  = { //Διαφοροποίησεις των 11,12 ...
                                    "ΔΕΚΑ ", "ΕΝΤΕΚΑ ",
                                    "ΔΩΔΕΚΑ " };
    private static string[] d   = { "", "ΔΕΚΑ", "ΕΙΚΟΣΙ ",
                                    "ΤΡΙΑΝΤΑ ", "ΣΑΡΑΝΤΑ ",
                                    "ΠΕΝΗΝΤΑ ", "ΕΞΗΝΤΑ ",
                                    "ΕΒΔΟΜΗΝΤΑ ", "ΟΓΔΟΝΤΑ ",
                                    "ΕΝΕΝΗΝΤΑ " };
    private static string[] e   = { "", "ΕΚΑΤΟ", "ΔΙΑΚΟΣΙ",
                                    "ΤΡΙΑΚΟΣΙ", "ΤΕΤΡΑΚΟΣΙ",
                                    "ΠΕΝΤΑΚΟΣΙ", "ΕΞΑΚΟΣΙ",
                                    "ΕΠΤΑΚΟΣΙ", "ΟΚΤΑΚΟΣΙ",
                                    "ΕΝΝΙΑΚΟΣΙ" };
    private static string[] idx = { "ΛΕΠΤΑ", "ΕΥΡΩ ", "ΧΙΛΙΑΔΕΣ ",
                                    "ΕΚΑΤΟΜΜΥΡΙ", "ΔΙΣ", "ΤΡΙΣ",
                                    "ΤΕΤΡΑΚΙΣ ", "ΠΕΝΤΑΚΙΣ " };

    public static double Round(double value)
    {
        return Round(value, 0);
    }

    public static double Round(double value, short precision)
    {
        return (double)Math.Round((decimal)value, precision);
    }

    public static string GetVerbal(double money)
    {
        return GetVerbal(money, true);
    }

    public static string GetVerbal(double money, bool showZero)
    {
        return GetVerbal(money, showZero, true);
    }

    public static string GetVerbal(double money, bool showZero,
                                   bool showCurrency )
    {
        string str;
        short index = 0;
        bool isZero = true;
        bool isNegative = false;

        str = "";

        if (money < 0)
        {
            money = -money;
            isNegative = true;
        }

        if (money != (long)money)
        {
            short value = (short)Round(100 * money
                                - 100 * Math.Floor(money), 0);
            if (value >= 100)
            {
                value -= 100;
                money += 1.0;
            }

            money = (long)money;
            if (value > 0)
            {
                isZero = false;

                if (money >= 1 && value > 0)
                {
                    str += "ΚΑΙ ";
                }
                str += GetValue(value, index, showCurrency);
            }
        }

        while (money >= 1)
        {
            isZero = false;
            short value = (short)((long)money % 1000);
            money /= 1000;
            index += 1;
            str = GetValue(value, index, showCurrency) + str;
            money = (long)money;
        }

        if (isZero)
        {
            if (showZero)
            {
                str = "ΜΗΔΕΝ ";
                if (showCurrency)
                {
                    str += idx[1];
                }
            }
        }
        else
        {
            if (isNegative)
                str.Insert(0, "MEION ");
        }

        return str;
    }

    static string GetValue( short money, short index,
                            bool showCurrency)
    {
        if (index == 2 && money == 1)
        {
            return "ΧΙΛΙΑ ";
        }

        string str = "";
        int dekmon = money % 100;
        int monades = dekmon % 10;
        int ekatontades = (int)(money / 100);
        int dekades = (int)(dekmon / 10);

        //EKATONTADES
        if (ekatontades == 1)
        {
            if (dekmon == 0)
            {
                str = e[1] + " ";
            }
            else
            {
                str = e[1] + "Ν ";
            }
        }
        else if (ekatontades > 1)
        {
            if (index == 2)
            {
                str = e[ekatontades] + "ΕΣ ";
            }
            else
            {
                str = e[ekatontades] + "Α ";
            }
        }

        //DEKADES
        switch (dekmon)
        {
            case 10:
                str += d1[monades];	//"ΔΕΚΑ " με κενό στο τέλος
                break;
            case 11:
                str += d1[monades];
                monades = 0;
                break;
            case 12:
                str += d1[monades];
                monades = 0;
                break;
            default:
                str += d[dekades];
                break;
        }

        //MONADES
        if ((index == 2) &&
            (monades == 1 || monades == 3 || monades == 4))
        {
            str += mF[monades];
        }
        else
        {
            if (dekmon < 10 || dekmon > 12)
            {
                str += m[monades];
            }
        }

        if (str.Length > 0 || index == 1)
        {
            if (index == 0 && money == 1)
            {
                if (showCurrency)
                {
                    str += "ΛΕΠΤΟ";
                }
            }
            else
            {
                if (index > 1 || showCurrency)
                {
                    str += idx[index];
                    if (index > 2)
                    {
                        if (index > 3)
                        {
                            str += idx[3];
                        }
                        if (money > 1)
                        {
                            str += "Α ";
                        }
                        else
                        {
                            str += "Ο ";
                        }
                    }
                }
            }
        }

        return str;
    }

} //class Money

3 Comments

  1. Ευχαριστώ πολύ φίλε μου!!
    Ο κώδικας σε Java είναι εδώ:
    http://openlogs.blogspot.com/2009/02/java.html

  2. Ευχαριστώ πολύ φίλε…
    Με γλύτωσες απο καμια ώρα γράψιμο κώδικα!!! 🙂

  3. Ωραία υλοποίηση, χρήσιμος κώδικας. Μπράβο.