CONVERSION D'UN CHIFFRE EN LETTRE

Cacophrene 263 Messages postés lundi 29 mars 2004Date d'inscription 4 mars 2008 Dernière intervention - 14 sept. 2006 à 08:46 - Dernière réponse : Whismeril 11412 Messages postés mardi 11 mars 2003Date d'inscriptionContributeurStatut 23 avril 2018 Dernière intervention
- 7 mars 2017 à 21:00
Cette discussion concerne un article du site. Pour la consulter dans son contexte d'origine, cliquez sur le lien ci-dessous.

http://codes-sources.commentcamarche.net/source/39539-conversion-d-un-chiffre-en-lettre

Afficher la suite 
Whismeril 11412 Messages postés mardi 11 mars 2003Date d'inscriptionContributeurStatut 23 avril 2018 Dernière intervention > bbb - 23 févr. 2017 à 21:38
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.
Whismeril 11412 Messages postés mardi 11 mars 2003Date d'inscriptionContributeurStatut 23 avril 2018 Dernière intervention > Whismeril 11412 Messages postés mardi 11 mars 2003Date d'inscriptionContributeurStatut 23 avril 2018 Dernière intervention - 1 mars 2017 à 00:47
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
    }
}
Whismeril 11412 Messages postés mardi 11 mars 2003Date d'inscriptionContributeurStatut 23 avril 2018 Dernière intervention > Whismeril 11412 Messages postés mardi 11 mars 2003Date d'inscriptionContributeurStatut 23 avril 2018 Dernière intervention - 1 mars 2017 à 21:18
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
    }
}
Whismeril 11412 Messages postés mardi 11 mars 2003Date d'inscriptionContributeurStatut 23 avril 2018 Dernière intervention > Whismeril 11412 Messages postés mardi 11 mars 2003Date d'inscriptionContributeurStatut 23 avril 2018 Dernière intervention - 7 mars 2017 à 21:00
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
Commenter la réponse de Cacophrene

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.