Conversion d'un chiffre en lettre

Soyez le premier à donner votre avis sur cette source.

Snippet vu 92 295 fois - Téléchargée 30 fois

Contenu du snippet

Ce module permet de convertir un chiffre entier de 0 à 99999999999999.

La méthode utilisée est la décomposition du chiffre par récursivité.
nous divisons le chiffre par les éléments suivant :
10^9 (milliard)
10^6 (million)
10^3 (millier)
100 (centaine)
10 (dizaine)
enfin il reste l'unité

Ex : 200905 = (2* 100 *1000) + (9 *100) + 5
soit (deux * cent * mille) + (neuf * cent) + cinq

Source / Exemple :


' Conversion de chiffre en lettre de 0 à 1999 milliard 999 999 999
Module ChLettre
    Dim chiffre() As String
    Dim dizaine() As String
    Dim chaine As String

    Private Sub init()
        ReDim dizaine(7) ' *** tableau contenant les noms des dizaines
        dizaine(1) = "dix"
        dizaine(2) = "vingt"
        dizaine(3) = "trente"
        dizaine(4) = "quarante"
        dizaine(5) = "cinquante"
        dizaine(6) = "soixante"

        ReDim chiffre(20) ' *** tableau contenant le nom des 19 premiers nombres en lettres
        chiffre(1) = "un"
        chiffre(2) = "deux"
        chiffre(3) = "trois"
        chiffre(4) = "quatre"
        chiffre(5) = "cinq"
        chiffre(6) = "six"
        chiffre(7) = "sept"
        chiffre(8) = "huit"
        chiffre(9) = "neuf"
        chiffre(10) = "dix"
        chiffre(11) = "onze"
        chiffre(12) = "douze"
        chiffre(13) = "treize"
        chiffre(14) = "quatorze"
        chiffre(15) = "quinze"
        chiffre(16) = "seize"
        chiffre(17) = "dix-sept"
        chiffre(18) = "dix-huit"
        chiffre(19) = "dix-neuf"
    End Sub
    Public Function NBLT(ByVal nb As Long) As String
        Call init()
        If nb = 0 Then
            NBLT = "Zéro"
            Exit Function
        End If
        chaine = ""
        Decompose(nb)
        chaine = Replace(chaine, "  ", " ")
        chaine = Replace(chaine, "- ", "-")
        NBLT = chaine
    End Function
    Private Function Decompose(ByVal Nombre As Long) As String
        Dim Reste As Long
        If Nombre > (10 ^ 9) Then

            Reste = Nombre Mod (10 ^ 9)
            Nombre = Nombre \ (10 ^ 9)

            If Nombre > 10 Then
                Decompose(Nombre)
            Else
                chaine += chiffre(Convert.ToInt16(Nombre))
            End If

            chaine += " milliard"
            If Nombre > 1 Then chaine += "s"

            Decompose(Reste)

        Else

            If Nombre > (10 ^ 6) Then

                Reste = Nombre Mod (10 ^ 6)
                Nombre = Nombre \ (10 ^ 6)

                If Nombre > 10 Then
                    Decompose(Nombre)
                Else
                    chaine += " " & chiffre(Convert.ToInt16(Nombre))

                End If

                chaine += " million"
                If Nombre > 1 Then chaine += "s"

                Decompose(Reste)

            Else
                If Nombre >= (10 ^ 3) Then

                    Reste = Nombre Mod (10 ^ 3)
                    Nombre = Nombre \ (10 ^ 3)

                    If Nombre > 10 Then
                        Decompose(Nombre)
                    Else
                        If Nombre > 1 Then chaine += " " & chiffre(Convert.ToInt16(Nombre))
                    End If

                    chaine += " mille"

                    Decompose(Reste)

                Else

                    If Nombre >= (100) Then

                        Reste = Nombre Mod (100)
                        Nombre = Nombre \ (100)

                        If Nombre > 10 Then
                            Decompose(Nombre)
                        Else
                            If Nombre > 1 Then chaine += " " & chiffre(Convert.ToInt16(Nombre))
                        End If

                        chaine += " cent"
                        If Nombre > 1 And Reste = 0 Then chaine += "s"

                        Decompose(Reste)

                    Else

                        If Nombre >= 80 And Nombre < 100 Then

                            Reste = Nombre Mod 20
                            Nombre = Nombre \ 20

                            If Nombre > 10 Then
                                Decompose(Nombre)
                            Else
                                chaine += " " & chiffre(Convert.ToInt16(Nombre))
                            End If

                            chaine += "-vingt"

                            Decompose(Reste)

                        Else

                            If Nombre < 20 And Nombre > 9 Then

                                chaine += " " & chiffre(Convert.ToInt16(Nombre))

                            Else

                                If Nombre > 19 And Nombre < 70 Then

                                    Reste = Nombre Mod 10
                                    Nombre = Nombre \ 10

                                    If Nombre > 10 Then
                                        Decompose(Nombre)
                                    Else
                                        chaine += " " & dizaine(Convert.ToInt16(Nombre))
                                    End If

                                    If Reste = 1 Then
                                        chaine += " et" ' Cas particlier (Ving et un , trante et un , etc...)
                                    Else
                                        If Reste <> 0 Then chaine += "-"
                                    End If

                                    Decompose(Reste)

                                Else

                                    If Nombre >= 70 Then

                                        chaine += " soixante"
                                        Reste = Nombre - 60

                                        If Reste = 1 Or Reste = 11 Then chaine += " et"

                                        Decompose(Reste)

                                    Else

                                        If Nombre < 10 Then chaine += " " & chiffre(Convert.ToInt16(Nombre))

                                    End If

                                End If
                            End If
                        End If
                    End If
                End If
            End If
        End If
    End Function
End Module

Conclusion :


Il a fallu adapté un peu le code en fonction des cas particuliers.(ex: 70,80,90)
Je reste à votre disposition pout toutes questions, commentaires et améliorations.

A voir également

Ajouter un commentaire

Commentaires

merciiiiiiiiiiiiiiiiiii
Messages postés
14823
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
22 mai 2020
401 > bbb
Bonsoir, la source date de 2006, à vue de nez elle doit être fonctionnelle (et à la lecture des commentaires), mais elle mélange Vb6 et VB.Net. Et même si souvent ça marche, parfois ça casse, donc autant éviter.
Le module et par extension les variables et méthodes globales vont à l'encontre du principe de la programmation objet, une classe Shared serait plus appropriée.
Call n'a plus aucune utilité en .Net
'Call Init() devient
Init()

A plusieurs reprises il y a des conversions en Int16, or .Net travaille en 32bits
chaine += " " & chiffre(Convert.ToInt16(Nombre))
donc pour aller lire la bonne valeur du tableau, après avoir converti nombre de double à int16, le complilateur va le reconvertir en int32. Ça fait perdre un peu de temps d'exécution.
Il y a d'autres points qui me chiffonnent, mais ne pouvant tester le code pour l'instant, je n'en dirais pas plus ce soir.
Messages postés
14823
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
22 mai 2020
401 >
Messages postés
14823
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
22 mai 2020

Bonsoir

finalement, je me suis dit qu'une méthode d'extension est à la fois pratique et un bon exemple.
Il s'agit d'une méthode que l'on vient ajouter à une classe existante (ici double), pour le coup, ça s'écrit dans un module.

Quelques lignes de test, et ça permet de comprendre l'utilité des méthodes d'extension
        Dim lesNombres As New List(Of String)()
        Dim nombreExemple As Double = 123.456
        lesNombres.Add(nombreExemple.ToLettres()) 'on peut appliquer la méthode d'extension sur une variable de type double
        lesNombres.Add(3210987654321.2.ToLettres()) 'on peut aussi l'appliquer directement sur un nombre (Attention, il faut une virgule, sinon le nombre est pris comme un entier et la méthode n'étend pas les entiers)
        lesNombres.Add(123456789012345.12.ToLettres()) 'ce nombre n'existe pas en double, c'est 123456789012345.12 qui est transmis à la méthode
        lesNombres.Add(1234.123456789.ToLettres())
        lesNombres.Add((-4321.987654321).ToLettres())
        lesNombres.Add(1.0E+16.ToLettres()) 'ce nombre est trop grand
        lesNombres.Add(0.12345678961.ToLettres()) 'il y a trop de chiffres dérrière la virgule, le resultat sera arrondi
        lesNombres.Add(6795432.456.ToLettres(Pays.Belgique, Devise.Euro))



Le code 100% vb.net
Imports System
Imports System.Collections.Generic

Public Module NombreEnLettres
    Private jusqueSeize() As String = {"zéro", "un", "deux", "trois", "quatre", "cinq", "six", "sept", "huit", "neuf", "dix", "onze", "douze", "treize", "quatorze", "quinze", "seize"}

    Private dizaines() As String = {"rien", "dix", "vingt", "trente", "quarante", "cinquante", "soixante", "soixante", "quatre-vingt", "quatre-vingt"}

    Private resultat As List(Of String)

    ''' <summary>
    ''' Méthode d'extension de la classe double écrivant le nombre en lettres
    ''' </summary>
    ''' <param name="Nombre">Nombre à écrire</param>
    ''' <param name="LePays">Pays d'utilisation, pour spécificitées régionnales</param>
    ''' <param name="LaDevise">Devise à utliser</param>
    ''' <returns></returns>
    <System.Runtime.CompilerServices.Extension> _
    Public Function ToLettres(ByVal Nombre As Double, Optional ByVal LePays As Pays = Pays.France, Optional ByVal LaDevise As Devise = Devise.Aucune) As String

        If Nombre >= 1.0E+16 Then
            Return "Nombre trop grand"
        End If

        resultat = New List(Of String)()

        Select Case Math.Sign(Nombre)
            Case -1
                resultat.Add("moins ")
                Nombre *= -1

            Case 0
                Return jusqueSeize(0)
        End Select

        Dim partieEntiere As Int64 = CLng(Math.Floor(Nombre))
        Dim partieDecimale As Double = Nombre - partieEntiere

        Dim milliers() As String = {"", "mille", "million", "milliard", "billion", "billiard"}

        If partieEntiere > 0 Then
            Dim troisChiffres As New List(Of Integer)() 'liste qui scinde la partie entière en morceaux de 3 chiffres

            Do While partieEntiere > 0
                troisChiffres.Add(CInt(Math.Floor(partieEntiere Mod 1000)))
                partieEntiere \= 1000
            Loop

            Dim reste As Double = Nombre - partieEntiere



            For i As Integer = troisChiffres.Count - 1 To 0 Step -1
                'INSTANT VB NOTE: The variable nombre was renamed since Visual Basic will not allow local variables with the same name as parameters or other local variables:
                Dim nombre_Renamed As Integer = troisChiffres(i)

                If nombre_Renamed > 1 Then 'valeurs de milliers au pluriel
                    resultat.Add(Ecrit3Chiffres(troisChiffres(i), LePays))
                    If i > 1 Then ' mille est invariable et "" ne prend pas de s
                        resultat.Add(milliers(i) & "s")
                    ElseIf i = 1 Then
                        resultat.Add(milliers(i))
                    End If
                ElseIf nombre_Renamed = 1 Then
                    resultat.Add("un")
                    resultat.Add(milliers(i))
                End If
                'on ne traite pas le 0, car on ne dit pas X millions zéro mille Y.
            Next i
        Else
            resultat.Add(jusqueSeize(0))
        End If

        Select Case LaDevise
            Case Devise.Dollar
                resultat.Add("$")

            Case Devise.Euro
                resultat.Add("€")

            Case Devise.FrancSuisse
                resultat.Add("CHF")

        End Select

        If LaDevise <> Devise.Aucune Then
            partieDecimale = Math.Round(partieDecimale, 2)
            If partieDecimale <> 0 Then
                resultat.Add("et")
                resultat.Add(Ecrire2Chiffres(CInt(Math.Floor(partieDecimale * 100)), LePays))
                resultat.Add("centimes")
            End If
        Else
            milliers = {"millième", "millionième", "milliardième"}

            'avec l'imprécision des nombres à virgules flotantes,  1234562.789 - 1234562 donne 0.78900000010617077 il faut donc compter le nombre de chiffres décimaux du nombre original et arrondir le resultat de la soustraction 
            Dim morceaux() As String = Nombre.ToString("G25").Split({"."c, ","c}) 'par défaut ToString arrondi à 10^-8, le format G25 oblige à écrire 25 caractères s'ils sont présents soit (au pire) 15 avant la virgule, la virgule et 9 après, split permet de découper le string obtenu

            If morceaux.Length = 2 Then 'il y a une partie décimale
                resultat.Add("et")

                Dim lenghtPartieDecimale As Integer = morceaux(1).Length
                If lenghtPartieDecimale > 9 Then
                    lenghtPartieDecimale = 9 'on se limite à 10^-9
                End If

                partieDecimale = Math.Round(partieDecimale, lenghtPartieDecimale)

                Dim i As Integer = 0
                Do While partieDecimale > 0
                    partieDecimale = partieDecimale * 1000
                    Dim valeur As Integer = CInt(Math.Floor(partieDecimale))
                    lenghtPartieDecimale -= 3
                    If lenghtPartieDecimale < 0 Then
                        lenghtPartieDecimale = 0
                    End If
                    partieDecimale = Math.Round(partieDecimale - valeur, lenghtPartieDecimale)

                    If valeur <> 0 Then
                        resultat.Add(Ecrit3Chiffres(valeur, LePays))
                        If valeur > 1 Then
                            resultat.Add(milliers(i) & "s")
                            i += 1
                        Else
                            resultat.Add(milliers(i))
                            i += 1
                        End If

                    End If
                Loop


            End If
        End If



        Return String.Join(" ", resultat)
    End Function

    ''' <summary>
    ''' Ecrit les nombres de 0 à 999
    ''' </summary>
    ''' <param name="Nombre">Nombre à écrire</param>
    ''' <param name="LePays">Pays d'utilisation, pour spécificitées régionnales</param>
    Private Function Ecrit3Chiffres(ByVal Nombre As Integer, ByVal LePays As Pays) As String
        If Nombre = 100 Then
            Return "cent"
        End If

        If Nombre < 100 Then
            Return Ecrire2Chiffres(Nombre, LePays)
        End If

        Dim centaine As Integer = Nombre \ 100
        Dim reste As Integer = Nombre Mod 100

        If reste = 0 Then 'Cent prend un s quand il est multiplié et non suivi d'un nombre, comme le cas de 100 est déjà traité on est face à un multiple
            Return jusqueSeize(centaine) & " cents"
        End If

        If centaine = 1 Then
            Return "cent " & Ecrire2Chiffres(reste, LePays) 'on ne dit pas un cent X, mais cent X
        End If

        Return jusqueSeize(centaine) & " cent " & Ecrire2Chiffres(reste, LePays)
    End Function

    ''' <summary>
    ''' Ecrit les nombres de 0 à 99
    ''' </summary>
    ''' <param name="Nombre">Nombre à écrire</param>
    ''' <param name="LePays">Pays d'utilisation, pour spécificitées régionnales</param>
    ''' <returns></returns>
    Private Function Ecrire2Chiffres(ByVal Nombre As Integer, ByVal LePays As Pays) As String
        If LePays <> Pays.France Then
            dizaines(7) = "septante"
            dizaines(9) = "nonante"
        End If
        If LePays = Pays.Suisse Then
            dizaines(8) = "huitante"
        End If

        If Nombre < 17 Then
            Return jusqueSeize(Nombre)
        End If

        Select Case Nombre 'cas particuliers de 71, 80 et 81
            Case 71 'en France 71 prend un et
                If LePays = Pays.France Then
                    Return "soixante et onze"
                End If

            Case 80 'en France et Belgique le vingt prend un s
                If LePays = Pays.Suisse Then
                    Return dizaines(8)
                Else
                    Return dizaines(8) & "s"
                End If

            Case 81 'en France et Belgique il n'y a pas de et
                If LePays <> Pays.Suisse Then
                    Return dizaines(8) & "-un"
                End If
        End Select


        Dim dizaine As Integer = Nombre \ 10
        Dim unite As Integer = Nombre Mod 10

        Dim laDizaine As String = dizaines(dizaine)

        If LePays = Pays.France AndAlso (dizaine = 7 OrElse dizaine = 9) Then
            dizaine -= 1
            unite += 10
        End If


        Select Case unite
            Case 0
                Return laDizaine

            Case 1
                Return laDizaine & " et un"

            Case 17, 18, 19 'pour 77 à 79 et 97 à 99
                unite = unite Mod 10
                Return laDizaine & "-dix-" & jusqueSeize(unite)

            Case Else
                Return laDizaine & "-" & jusqueSeize(unite)
        End Select
    End Function
End Module

Public Enum Pays
    France
    Belgique
    Suisse
End Enum

Public Enum Devise
    Aucune
    Euro
    FrancSuisse
    Dollar
End Enum



Pour les règles d'orthographe je me suis basé sur ce site
http://leconjugueur.lefigaro.fr/frlesnombres.php

J'ai aussi appliqué des critères utilisés pour cette autre source
http://www.commentcamarche.net/faq/11100-vb6-net-vba-transformer-chiffres-en-lettre

Je donne aussi le code en C#. Les modules n'existant pas dans ce langage, les extensions s'écrivent dans l’équivalent d'une classe Shared => la classe static (qui n'a pas le même sens qu'en vb).
using System;
using System.Collections.Generic;

namespace test
{
    public static class NombreEnLettres
    {
        private static string[] jusqueSeize = { "zéro", "un", "deux", "trois", "quatre", "cinq", "six", "sept", "huit", "neuf", "dix", "onze", "douze", "treize", "quatorze", "quinze", "seize" };

        private static string[] dizaines = { "rien", "dix", "vingt", "trente", "quarante", "cinquante", "soixante", "soixante", "quatre-vingt", "quatre-vingt"};

        private static List<string> resultat;

        /// <summary>
        /// Méthode d'extension de la classe double écrivant le nombre en lettres
        /// </summary>
        /// <param name="Nombre">Nombre à écrire</param>
        /// <param name="LePays">Pays d'utilisation, pour spécificitées régionnales</param>
        /// <param name="LaDevise">Devise à utliser</param>
        /// <returns></returns>
        public static string ToLettres(this double Nombre, Pays LePays = Pays.France, Devise LaDevise = Devise.Aucune)
        {

            if (Nombre >= 1e16)
                return "Nombre trop grand";

            resultat = new List<string>();

            switch (Math.Sign(Nombre))
            {
                case -1:
                    resultat.Add("moins ");
                    Nombre *= -1;
                    break;

                case 0:
                    return jusqueSeize[0];
            }
            
            Int64 partieEntiere = (Int64)(Nombre);
            double partieDecimale = Nombre - partieEntiere;

            string[] milliers = { "", "mille", "million", "milliard", "billion", "billiard" };

            if (partieEntiere > 0)
            {
                List<int> troisChiffres = new List<int>();//liste qui scinde la partie entière en morceaux de 3 chiffres

                while (partieEntiere > 0)
                {
                    troisChiffres.Add((int)(partieEntiere % 1000));
                    partieEntiere /= 1000;
                }

                double reste = Nombre - partieEntiere;



                for (int i = troisChiffres.Count - 1; i >= 0; i--)
                {
                    int nombre = troisChiffres[i];

                    if (nombre > 1)//valeurs de milliers au pluriel
                    {
                        resultat.Add(Ecrit3Chiffres(troisChiffres[i], LePays));
                        if (i > 1)// mille est invariable et "" ne prend pas de s 
                            resultat.Add(milliers[i] + "s");
                        else if (i == 1)
                            resultat.Add(milliers[i]);
                    }
                    else if (nombre == 1)
                    {
                        resultat.Add("un");
                        resultat.Add(milliers[i]);
                    }
                    //on ne traite pas le 0, car on ne dit pas X millions zéro mille Y.
                }
            }
            else
                resultat.Add(jusqueSeize[0]);
            
            switch(LaDevise)
            {
                case Devise.Dollar:
                    resultat.Add("$");
                    break;

                case Devise.Euro:
                    resultat.Add("€");
                    break;

                case Devise.FrancSuisse:
                    resultat.Add("CHF");
                    break;

            }

            if (LaDevise != Devise.Aucune)
            {
                partieDecimale = Math.Round(partieDecimale, 2);
                if (partieDecimale != 0)
                {
                    resultat.Add("et");
                    resultat.Add(Ecrire2Chiffres((int)(partieDecimale * 100), LePays));
                    resultat.Add("centimes");
                }
            }
            else
            {
                milliers = new[] { "millième", "millionième", "milliardième" };

                //avec l'imprécision des nombres à virgules flotantes,  1234562.789 - 1234562 donne 0.78900000010617077 il faut donc compter le nombre de chiffres décimaux du nombre original et arrondir le resultat de la soustraction 
                string[] morceaux = Nombre.ToString("G25").Split(new []{'.',','});//par défaut ToString arrondi à 10^-8, le format G25 oblige à écrire 25 caractères s'ils sont présents soit (au pire) 15 avant la virgule, la virgule et 9 après, split permet de découper le string obtenu

                if (morceaux.Length == 2)//il y a une partie décimale
                {
                    resultat.Add("et");

                    int lenghtPartieDecimale = morceaux[1].Length;
                    if (lenghtPartieDecimale > 9)
                        lenghtPartieDecimale = 9;//on se limite à 10^-9

                    partieDecimale = Math.Round(partieDecimale, lenghtPartieDecimale);

                    int i = 0;
                    while (partieDecimale > 0)
                    {
                        partieDecimale = partieDecimale * 1000;
                        int valeur = (int)partieDecimale;
                        lenghtPartieDecimale -= 3;
                        if (lenghtPartieDecimale < 0)
                            lenghtPartieDecimale = 0;
                        partieDecimale = Math.Round(partieDecimale - valeur, lenghtPartieDecimale);

                        if (valeur != 0)
                        {
                            resultat.Add(Ecrit3Chiffres(valeur, LePays));
                            if (valeur > 1)
                                resultat.Add(milliers[i++] + "s");
                            else
                                resultat.Add(milliers[i++]);

                        }
                    }


                }
            }



            return string.Join(" ", resultat);
        }

        /// <summary>
        /// Ecrit les nombres de 0 à 999
        /// </summary>
        /// <param name="Nombre">Nombre à écrire</param>
        /// <param name="LePays">Pays d'utilisation, pour spécificitées régionnales</param>
        private static string Ecrit3Chiffres(int Nombre, Pays LePays)
        {
            if (Nombre == 100)
                return "cent";

            if(Nombre < 100)
                return Ecrire2Chiffres(Nombre, LePays);

            int centaine = Nombre / 100;
            int reste = Nombre % 100;

            if (reste == 0)//Cent prend un s quand il est multiplié et non suivi d'un nombre, comme le cas de 100 est déjà traité on est face à un multiple
                return jusqueSeize[centaine] + " cents";

            if (centaine == 1)
                return "cent " + Ecrire2Chiffres(reste, LePays);//on ne dit pas un cent X, mais cent X

            return jusqueSeize[centaine] + " cent " + Ecrire2Chiffres(reste, LePays);
        }

        /// <summary>
        /// Ecrit les nombres de 0 à 99
        /// </summary>
        /// <param name="Nombre">Nombre à écrire</param>
        /// <param name="LePays">Pays d'utilisation, pour spécificitées régionnales</param>
        /// <returns></returns>
        private static string Ecrire2Chiffres(int Nombre, Pays LePays)
        {
            if (LePays != Pays.France)
            {
                dizaines[7] = "septante";
                dizaines[9] = "nonante";
            }
            if (LePays == Pays.Suisse)
                dizaines[8] = "huitante";

            if (Nombre < 17)
                return jusqueSeize[Nombre];

            switch (Nombre)//cas particuliers de 71, 80 et 81
            {
                case 71://en France 71 prend un et
                    if (LePays == Pays.France)
                        return "soixante et onze";
                    break;

                case 80://en France et Belgique le vingt prend un s
                    if (LePays == Pays.Suisse)
                        return dizaines[8];
                    else
                        return dizaines[8] + "s";

                case 81://en France et Belgique il n'y a pas de et
                    if (LePays != Pays.Suisse)
                        return dizaines[8] + "-un";
                    break;
            }


            int dizaine = Nombre / 10;
            int unite = Nombre % 10;

            string laDizaine = dizaines[dizaine];

            if (LePays == Pays.France && (dizaine == 7 || dizaine == 9))
            {
                dizaine--;
                unite += 10;
            }


            switch (unite)
            {
                case 0:
                    return laDizaine;

                case 1:
                    return laDizaine + " et un";

                case 17://pour 77 à 79 et 97 à 99
                case 18:
                case 19:
                    unite = unite % 10;
                    return laDizaine + "-dix-" + jusqueSeize[unite];

                default:
                    return laDizaine + "-" + jusqueSeize[unite];
            }
        }
    }

    public enum Pays
    {
        France,
        Belgique,
        Suisse
    }

    public enum Devise
    {
        Aucune,
        Euro,
        FrancSuisse,
        Dollar
    }
}
Messages postés
14823
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
22 mai 2020
401 >
Messages postés
14823
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
22 mai 2020

En transposant le code en VBA, j'ai trouvé 2 erreurs:
  • ça écrivait un mille au lieu de mille
  • ça testait si le nombre est trop grand en positif, mais pas en négatif

voici les corrections

VB.Net
Imports System
Imports System.Collections.Generic

Public Module NombreEnLettres
    Private jusqueSeize() As String = {"zéro", "un", "deux", "trois", "quatre", "cinq", "six", "sept", "huit", "neuf", "dix", "onze", "douze", "treize", "quatorze", "quinze", "seize"}

    Private dizaines() As String = {"rien", "dix", "vingt", "trente", "quarante", "cinquante", "soixante", "soixante", "quatre-vingt", "quatre-vingt"}

    Private resultat As List(Of String)

    ''' <summary>
    ''' Méthode d'extension de la classe double écrivant le nombre en lettres
    ''' </summary>
    ''' <param name="Nombre">Nombre à écrire</param>
    ''' <param name="LePays">Pays d'utilisation, pour spécificitées régionnales</param>
    ''' <param name="LaDevise">Devise à utliser</param>
    ''' <returns></returns>
    <System.Runtime.CompilerServices.Extension> _
    Public Function ToLettres(ByVal Nombre As Double, Optional ByVal LePays As Pays = Pays.France, Optional ByVal LaDevise As Devise = Devise.Aucune) As String

        resultat = New List(Of String)()

        Select Case Math.Sign(Nombre)
            Case -1
                resultat.Add("moins ")
                Nombre *= -1

            Case 0
                Return jusqueSeize(0)
        End Select

        If Nombre >= 1.0E+16 Then
            Return "Nombre trop grand"
        End If


        Dim partieEntiere As Int64 = CLng(Math.Floor(Nombre))
        Dim partieDecimale As Double = Nombre - partieEntiere

        Dim milliers() As String = {"", "mille", "million", "milliard", "billion", "billiard"}

        If partieEntiere > 0 Then
            Dim troisChiffres As New List(Of Integer)() 'liste qui scinde la partie entière en morceaux de 3 chiffres

            Do While partieEntiere > 0
                troisChiffres.Add(CInt(Math.Floor(partieEntiere Mod 1000)))
                partieEntiere \= 1000
            Loop

            Dim reste As Double = Nombre - partieEntiere

            For i As Integer = troisChiffres.Count - 1 To 0 Step -1
                Dim leNombre As Integer = troisChiffres(i)

                If leNombre > 1 Then 'valeurs de milliers au pluriel
                    resultat.Add(Ecrit3Chiffres(troisChiffres(i), LePays))
                    If i > 1 Then ' mille est invariable et "" ne prend pas de s
                        resultat.Add(milliers(i) & "s")
                    ElseIf i = 1 Then
                        resultat.Add(milliers(i))
                    End If
                ElseIf leNombre = 1 Then
                    If i <> 1 Then resultat.Add("un") 'on dit un million, mais pas un mille
                    resultat.Add(milliers(i))
                End If
                'on ne traite pas le 0, car on ne dit pas X millions zéro mille Y.
            Next i
        Else
            resultat.Add(jusqueSeize(0))
        End If

        Select Case LaDevise
            Case Devise.Dollar
                resultat.Add("$")

            Case Devise.Euro
                resultat.Add("€")

            Case Devise.FrancSuisse
                resultat.Add("CHF")

        End Select

        If LaDevise <> Devise.Aucune Then
            partieDecimale = Math.Round(partieDecimale, 2)
            If partieDecimale <> 0 Then
                resultat.Add("et")
                resultat.Add(Ecrire2Chiffres(CInt(Math.Floor(partieDecimale * 100)), LePays))
                resultat.Add("centimes")
            End If
        Else
            milliers = {"millième", "millionième", "milliardième"}

            'avec l'imprécision des nombres à virgules flotantes,  1234562.789 - 1234562 donne 0.78900000010617077 il faut donc compter le nombre de chiffres décimaux du nombre original et arrondir le resultat de la soustraction 
            Dim morceaux() As String = Nombre.ToString("G25").Split({"."c, ","c}) 'par défaut ToString arrondi à 10^-8, le format G25 oblige à écrire 25 caractères s'ils sont présents soit (au pire) 15 avant la virgule, la virgule et 9 après, split permet de découper le string obtenu

            If morceaux.Length = 2 Then 'il y a une partie décimale
                resultat.Add("et")

                Dim lenghtPartieDecimale As Integer = morceaux(1).Length
                If lenghtPartieDecimale > 9 Then
                    lenghtPartieDecimale = 9 'on se limite à 10^-9
                End If

                partieDecimale = Math.Round(partieDecimale, lenghtPartieDecimale)

                Dim i As Integer = 0
                Do While partieDecimale > 0
                    partieDecimale = partieDecimale * 1000
                    Dim valeur As Integer = CInt(Math.Floor(partieDecimale))
                    lenghtPartieDecimale -= 3
                    If lenghtPartieDecimale < 0 Then
                        lenghtPartieDecimale = 0
                    End If
                    partieDecimale = Math.Round(partieDecimale - valeur, lenghtPartieDecimale)

                    If valeur <> 0 Then
                        resultat.Add(Ecrit3Chiffres(valeur, LePays))
                        If valeur > 1 Then
                            resultat.Add(milliers(i) & "s")
                            i += 1
                        Else
                            resultat.Add(milliers(i))
                            i += 1
                        End If

                    End If
                Loop


            End If
        End If



        Return String.Join(" ", resultat)
    End Function

    ''' <summary>
    ''' Ecrit les nombres de 0 à 999
    ''' </summary>
    ''' <param name="Nombre">Nombre à écrire</param>
    ''' <param name="LePays">Pays d'utilisation, pour spécificitées régionnales</param>
    Private Function Ecrit3Chiffres(ByVal Nombre As Integer, ByVal LePays As Pays) As String
        If Nombre = 100 Then
            Return "cent"
        End If

        If Nombre < 100 Then
            Return Ecrire2Chiffres(Nombre, LePays)
        End If

        Dim centaine As Integer = Nombre \ 100
        Dim reste As Integer = Nombre Mod 100

        If reste = 0 Then 'Cent prend un s quand il est multiplié et non suivi d'un nombre, comme le cas de 100 est déjà traité on est face à un multiple
            Return jusqueSeize(centaine) & " cents"
        End If

        If centaine = 1 Then
            Return "cent " & Ecrire2Chiffres(reste, LePays) 'on ne dit pas un cent X, mais cent X
        End If

        Return jusqueSeize(centaine) & " cent " & Ecrire2Chiffres(reste, LePays)
    End Function

    ''' <summary>
    ''' Ecrit les nombres de 0 à 99
    ''' </summary>
    ''' <param name="Nombre">Nombre à écrire</param>
    ''' <param name="LePays">Pays d'utilisation, pour spécificitées régionnales</param>
    ''' <returns></returns>
    Private Function Ecrire2Chiffres(ByVal Nombre As Integer, ByVal LePays As Pays) As String
        If LePays <> Pays.France Then
            dizaines(7) = "septante"
            dizaines(9) = "nonante"
        End If
        If LePays = Pays.Suisse Then
            dizaines(8) = "huitante"
        End If

        If Nombre < 17 Then
            Return jusqueSeize(Nombre)
        End If

        Select Case Nombre 'cas particuliers de 71, 80 et 81
            Case 71 'en France 71 prend un et
                If LePays = Pays.France Then
                    Return "soixante et onze"
                End If

            Case 80 'en France et Belgique le vingt prend un s
                If LePays = Pays.Suisse Then
                    Return dizaines(8)
                Else
                    Return dizaines(8) & "s"
                End If

            Case 81 'en France et Belgique il n'y a pas de et
                If LePays <> Pays.Suisse Then
                    Return dizaines(8) & "-un"
                End If
        End Select


        Dim dizaine As Integer = Nombre \ 10
        Dim unite As Integer = Nombre Mod 10

        Dim laDizaine As String = dizaines(dizaine)

        If LePays = Pays.France AndAlso (dizaine = 7 OrElse dizaine = 9) Then
            dizaine -= 1
            unite += 10
        End If


        Select Case unite
            Case 0
                Return laDizaine

            Case 1
                Return laDizaine & " et un"

            Case 17, 18, 19 'pour 77 à 79 et 97 à 99
                unite = unite Mod 10
                Return laDizaine & "-dix-" & jusqueSeize(unite)

            Case Else
                Return laDizaine & "-" & jusqueSeize(unite)
        End Select
    End Function
End Module

Public Enum Pays
    France
    Belgique
    Suisse
End Enum

Public Enum Devise
    Aucune
    Euro
    FrancSuisse
    Dollar
End Enum



C#
using System;
using System.Collections.Generic;

namespace test
{
    public static class NombreEnLettres
    {
        private static string[] jusqueSeize = { "zéro", "un", "deux", "trois", "quatre", "cinq", "six", "sept", "huit", "neuf", "dix", "onze", "douze", "treize", "quatorze", "quinze", "seize" };

        private static string[] dizaines = { "rien", "dix", "vingt", "trente", "quarante", "cinquante", "soixante", "soixante", "quatre-vingt", "quatre-vingt"};

        private static List<string> resultat;

        /// <summary>
        /// Méthode d'extension de la classe double écrivant le nombre en lettres
        /// </summary>
        /// <param name="Nombre">Nombre à écrire</param>
        /// <param name="LePays">Pays d'utilisation, pour spécificitées régionnales</param>
        /// <param name="LaDevise">Devise à utliser</param>
        /// <returns></returns>
        public static string ToLettres(this double Nombre, Pays LePays = Pays.France, Devise LaDevise = Devise.Aucune)
        {

            resultat = new List<string>();

            switch (Math.Sign(Nombre))
            {
                case -1:
                    resultat.Add("moins ");
                    Nombre *= -1;
                    break;

                case 0:
                    return jusqueSeize[0];
            }

            if (Nombre >= 1e16)
                return "Nombre trop grand";

            
            Int64 partieEntiere = (Int64)(Nombre);
            double partieDecimale = Nombre - partieEntiere;

            string[] milliers = { "", "mille", "million", "milliard", "billion", "billiard" };

            if (partieEntiere > 0)
            {
                List<int> troisChiffres = new List<int>();//liste qui scinde la partie entière en morceaux de 3 chiffres

                while (partieEntiere > 0)
                {
                    troisChiffres.Add((int)(partieEntiere % 1000));
                    partieEntiere /= 1000;
                }

                double reste = Nombre - partieEntiere;



                for (int i = troisChiffres.Count - 1; i >= 0; i--)
                {
                    int nombre = troisChiffres[i];

                    if (nombre > 1)//valeurs de milliers au pluriel
                    {
                        resultat.Add(Ecrit3Chiffres(troisChiffres[i], LePays));
                        if (i > 1)// mille est invariable et "" ne prend pas de s 
                            resultat.Add(milliers[i] + "s");
                        else if (i == 1)
                            resultat.Add(milliers[i]);
                    }
                    else if (nombre == 1)
                    {
                        if (i != 1) resultat.Add("un");//on dit un million, mais pas un mille
                        resultat.Add(milliers[i]);
                    }
                    //on ne traite pas le 0, car on ne dit pas X millions zéro mille Y.
                }
            }
            else
                resultat.Add(jusqueSeize[0]);
            
            switch(LaDevise)
            {
                case Devise.Dollar:
                    resultat.Add("$");
                    break;

                case Devise.Euro:
                    resultat.Add("€");
                    break;

                case Devise.FrancSuisse:
                    resultat.Add("CHF");
                    break;

            }

            if (LaDevise != Devise.Aucune)
            {
                partieDecimale = Math.Round(partieDecimale, 2);
                if (partieDecimale != 0)
                {
                    resultat.Add("et");
                    resultat.Add(Ecrire2Chiffres((int)(partieDecimale * 100), LePays));
                    resultat.Add("centimes");
                }
            }
            else
            {
                milliers = new[] { "millième", "millionième", "milliardième" };

                //avec l'imprécision des nombres à virgules flotantes,  1234562.789 - 1234562 donne 0.78900000010617077 il faut donc compter le nombre de chiffres décimaux du nombre original et arrondir le resultat de la soustraction 
                string[] morceaux = Nombre.ToString("G25").Split(new []{'.',','});//par défaut ToString arrondi à 10^-8, le format G25 oblige à écrire 25 caractères s'ils sont présents soit (au pire) 15 avant la virgule, la virgule et 9 après, split permet de découper le string obtenu

                if (morceaux.Length == 2)//il y a une partie décimale
                {
                    resultat.Add("et");

                    int lenghtPartieDecimale = morceaux[1].Length;
                    if (lenghtPartieDecimale > 9)
                        lenghtPartieDecimale = 9;//on se limite à 10^-9

                    partieDecimale = Math.Round(partieDecimale, lenghtPartieDecimale);

                    int i = 0;
                    while (partieDecimale > 0)
                    {
                        partieDecimale = partieDecimale * 1000;
                        int valeur = (int)partieDecimale;
                        lenghtPartieDecimale -= 3;
                        if (lenghtPartieDecimale < 0)
                            lenghtPartieDecimale = 0;
                        partieDecimale = Math.Round(partieDecimale - valeur, lenghtPartieDecimale);

                        if (valeur != 0)
                        {
                            resultat.Add(Ecrit3Chiffres(valeur, LePays));
                            if (valeur > 1)
                                resultat.Add(milliers[i++] + "s");
                            else
                                resultat.Add(milliers[i++]);

                        }
                    }


                }
            }



            return string.Join(" ", resultat);
        }

        /// <summary>
        /// Ecrit les nombres de 0 à 999
        /// </summary>
        /// <param name="Nombre">Nombre à écrire</param>
        /// <param name="LePays">Pays d'utilisation, pour spécificitées régionnales</param>
        private static string Ecrit3Chiffres(int Nombre, Pays LePays)
        {
            if (Nombre == 100)
                return "cent";

            if(Nombre < 100)
                return Ecrire2Chiffres(Nombre, LePays);

            int centaine = Nombre / 100;
            int reste = Nombre % 100;

            if (reste == 0)//Cent prend un s quand il est multiplié et non suivi d'un nombre, comme le cas de 100 est déjà traité on est face à un multiple
                return jusqueSeize[centaine] + " cents";

            if (centaine == 1)
                return "cent " + Ecrire2Chiffres(reste, LePays);//on ne dit pas un cent X, mais cent X

            return jusqueSeize[centaine] + " cent " + Ecrire2Chiffres(reste, LePays);
        }

        /// <summary>
        /// Ecrit les nombres de 0 à 99
        /// </summary>
        /// <param name="Nombre">Nombre à écrire</param>
        /// <param name="LePays">Pays d'utilisation, pour spécificitées régionnales</param>
        /// <returns></returns>
        private static string Ecrire2Chiffres(int Nombre, Pays LePays)
        {
            if (LePays != Pays.France)
            {
                dizaines[7] = "septante";
                dizaines[9] = "nonante";
            }
            if (LePays == Pays.Suisse)
                dizaines[8] = "huitante";

            if (Nombre < 17)
                return jusqueSeize[Nombre];

            switch (Nombre)//cas particuliers de 71, 80 et 81
            {
                case 71://en France 71 prend un et
                    if (LePays == Pays.France)
                        return "soixante et onze";
                    break;

                case 80://en France et Belgique le vingt prend un s
                    if (LePays == Pays.Suisse)
                        return dizaines[8];
                    else
                        return dizaines[8] + "s";

                case 81://en France et Belgique il n'y a pas de et
                    if (LePays != Pays.Suisse)
                        return dizaines[8] + "-un";
                    break;
            }


            int dizaine = Nombre / 10;
            int unite = Nombre % 10;

            string laDizaine = dizaines[dizaine];

            if (LePays == Pays.France && (dizaine == 7 || dizaine == 9))
            {
                dizaine--;
                unite += 10;
            }


            switch (unite)
            {
                case 0:
                    return laDizaine;

                case 1:
                    return laDizaine + " et un";

                case 17://pour 77 à 79 et 97 à 99
                case 18:
                case 19:
                    unite = unite % 10;
                    return laDizaine + "-dix-" + jusqueSeize[unite];

                default:
                    return laDizaine + "-" + jusqueSeize[unite];
            }
        }
    }

    public enum Pays
    {
        France,
        Belgique,
        Suisse
    }

    public enum Devise
    {
        Aucune,
        Euro,
        FrancSuisse,
        Dollar
    }
}
Messages postés
14823
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
22 mai 2020
401 >
Messages postés
14823
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
22 mai 2020

Suite à une erreur relevée sur un script JS similaire, j'ai fait une correction.
Je l'ai postée là
http://codes-sources.commentcamarche.net/source/101858-ecrire-des-nombres-en-lettre-c-vb-net-et-vba
Afficher les 13 commentaires

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.