Archivi tag: c#

Parsing dei parametri C# e VB.NET

Dovete realizzare una applicazione console in ambiente .Net, con parametri in riga di comando? Non perdete tempo a creare routine custom per verificare la presenza dei parametri, lasciate fare tutto a CommandLineParser. L’installazione è semplice da NuGet. Basta fornire una classe modello con gli opportuni metadati e richiamare il parser, in output otterrete l’oggetto con i valori dei parametri popolati.

Ad esempio:

using System;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using System.Diagnostics;
using System.Threading;
using CommandLine;

namespace TxtTrasformation
{
    internal class Program
    {
        public class Options
        {
            [Option('f', "FilePath", Required = true, HelpText = "Inserisci il nome file da elaborare")]
            public string  FilePath { get; set; }
        }
        private static void Main(string[] args)
        {
            Parser.Default.ParseArguments<Options>(args)
                   .WithParsed<Options>(o =>
                   {
                       ElaboraFile(o.FilePath);
                   });
        }
        static void ElaboraFile(string filein) {
            Stopwatch sw = new Stopwatch();
            sw.Start();
/*
Elaborazione...
*/
            sw.Stop();

        }
    }
}

La classe Options definisce un parametro obbiligatorio “f” di tipo testo. Se il parsing dei parametri fallisce, viene automaticamente visualizzata la schermata di riepilogo dei parametri. In alternativa si può gestire l’errore nella funzione:

.WithNotParsed((errs) => HandleParseError(errs));

Scriver numeri in lettere ROMANE in C#

Dop il ICustomFromatter per scrivere numeri in lettere, ecco un’altro FormatProvider per scrivere un numero intero da cifre arabe in cifre romane:

public class RomanFormatProvider : IFormatProvider, ICustomFormatter
    {

        IFormatProvider _parent;

        public RomanFormatProvider() : this(CultureInfo.CurrentCulture) { }
        public RomanFormatProvider(IFormatProvider parent)
        {
            _parent = parent;
        }

        public object GetFormat(Type formatType)
        {
            if (formatType == typeof(ICustomFormatter)) return this;
            return null;
        }

        public string Format(string format, object arg, IFormatProvider prov)
        {

            if (arg == null || format != "RO")
                return string.Format(_parent, "{0:" + format + "}", arg);

            return ToRoman(arg.ToString());
        }

        private string ToRoman(string n)
        {
            StringBuilder r = new StringBuilder();

            int i = 0;
            foreach (var c in n)
            {
                r.Append(calcDigit(int.Parse(c.ToString()), n.Length  - i - 1));
                i++;
            }
            return r.ToString();
        }

        class Level
        {
            public Level(string i, string v, string x)
            {
                this.i = i;
                this.v = v;
                this.x = x;
            }
            public string i { get; set; }
            public string v { get; set; }
            public string x { get; set; }

        }

        static Level[] levels = new RomanFormatProvider.Level[] {
            new Level("I", "V", "X"),
            new Level("X", "L", "C"),
            new Level("C", "D", "M")
        };

        string calcDigit(int d, int l)
        {
            string str;
            if (l > 2)
            {
                str = "";
                for (var k = 1; k <= d * Math.Pow (10, l - 3); k++)
                    str += "M";
                return str;
            }
            else
                switch (d)
                {
                    case 1:
                        return levels[l].i;
                         
                    case 2:
                        return levels[l].i + levels[l].i;
                         
                    case 3:
                        return levels[l].i + levels[l].i + levels[l].i;
                       
                    case 4:
                        return levels[l].i + levels[l].v;
                       
                    case 5:
                        return levels[l].v;
                       
                    case 6:
                        return levels[l].v + levels[l].i;
                       
                    case 7:
                        return levels[l].v + levels[l].i + levels[l].i;
                       
                    case 8:
                        return levels[l].v + levels[l].i + levels[l].i + levels[l].i;
                       
                    case 9:
                        return levels[l].i + levels[l].x;
                        
                    default:
                        return "";
                        
                }
        }
    }

Con questo CustomFormatter è possibile scrivere semplicemente:

RomanFormatProvider fr = new RomanFormatProvider();
s = string.Format(fr, "Il numero {0} in lettere è {0:RO}", 1971);
Console.WriteLine(s);

Il cui output è:

Il numero 1971 in lettere è MCMLXXI

 

Scrivere numeri in lettere in C#

Il framework .Net offre diversi strumenti per scrivere o leggere in vari tipi dati da/verso stringhe. Una conversione molto particolare è quella di scrivere un numero invece che in cifre a parole, ad esempio 1234 in milleduecentotrentaquattro. Un modo per eseguire questa conversione in maniera integrata con il resto del framework è quella di implementare le interfacce IFormatProvider e ICustomFormatter. Partendo dall’idea di base fornita da Joseph Albahari nel suo C# 6 in a nutshell ho realizzato una classe che esegue la conversione per la lingua italiana:

 

public class WordyFormatProviderITA : IFormatProvider, ICustomFormatter
    {

        IFormatProvider _parent;    

        public WordyFormatProviderITA() : this(CultureInfo.CurrentCulture) { }
        public WordyFormatProviderITA(IFormatProvider parent)
        {
            _parent = parent;
        }

        public object GetFormat(Type formatType)
        {
            if (formatType == typeof(ICustomFormatter)) return this;
            return null;
        }

        public string Format(string format, object arg, IFormatProvider prov)
        {
            // If it's not our format string, defer to the parent provider:
            if (arg == null || format==null || !format.StartsWith("W"))
                return string.Format(_parent, "{0:" + format + "}", arg);

            int c = format.IndexOf(".") == -1 ? 2 : int.Parse(format.Replace("W.",""));
            if (arg is double || arg is float || arg is decimal )
            {
                decimal num = Convert.ToDecimal(arg);
                long parteIntera = (long)Decimal.Truncate(num);
                int parteDecimale = (int)(Math.Round(num - parteIntera, c) * (decimal)Math.Pow(10,c));
                return convertNumberToReadableString(parteIntera) + "/" + parteDecimale.ToString();
            }            
            long l = 0;
            if (long.TryParse(arg.ToString(), out l))
            {
                return convertNumberToReadableString(l);
            }
            return "Invalid argument";
        }

        static readonly string[] unita = { "zero", "uno", "due", "tre", "quattro", "cinque", "sei", "sette", "otto", "nove", "dieci", "undici", "dodici", "tredici", "quattordici", "quindici", "sedici", "diciassette", "diciotto", "diciannove" };
        static readonly string[] decine = { "", "dieci", "venti", "trenta", "quaranta", "cinquanta", "sessanta", "settanta", "ottonta", "novanta" };

        public string convertNumberToReadableString(long num)
        {
            StringBuilder result = new StringBuilder();
            long mod = 0;
            long i = 0;
            
            if (num > 0 && num < 20)
            {
                result.Append( unita[num]);
            }
            else
            {
                if (num < 100)
                {
                    mod = num % 10;
                    i = num / 10;
                    switch (mod)
                    {
                        case 0:
                            result.Append(decine[i]);
                            break;
                        case 1:
                            result.Append(decine[i].Substring(0, decine[i].Length - 1));
                            result.Append(unita[mod]);
                            break;
                        case 8:
                            result.Append(decine[i].Substring(0, decine[i].Length - 1));
                            result.Append(unita[mod]);
                            break;
                        default:
                            result.Append(decine[i] + unita[mod]);
                            break;
                    }
                }
                else
                {
                    if (num < 1000)
                    {
                        mod = num % 100;
                        i = (num - mod) / 100;
                        switch (i)
                        {
                            case 1:
                                result.Append("cento");
                                break;
                            default:
                                result.Append(unita[i]);
                                result.Append("cento");
                                break;
                        }
                        result.Append(convertNumberToReadableString(mod));
                    }
                    else
                    {
                        if (num < 10000)
                        {
                            mod = num % 1000;
                            i = (num - mod) / 1000;
                            switch (i)
                            {
                                case 1:
                                    result.Append("mille");
                                    break;
                                default:
                                    result.Append(unita[i]);
                                    result.Append("mila");
                                    break;
                            }
                            result.Append(convertNumberToReadableString(mod));
                        }
                        else
                        {
                            if (num < 1000000)
                            {
                                mod = num % 1000;
                                i = (num - mod) / 1000;
                                switch ((num - mod) / 1000)
                                {
                                    default:
                                        if (i < 20)
                                        {
                                            result.Append(unita[i]);
                                            result.Append("mila");
                                        }
                                        else
                                        {
                                            result.Append(convertNumberToReadableString(i));
                                            result.Append("mila");
                                        }
                                        break;
                                }
                                result.Append(convertNumberToReadableString(mod));
                            }
                            else
                            {
                                if (num < 1000000000)
                                {
                                    mod = num % 1000000;
                                    i = (num - mod) / 1000000;
                                    switch (i)
                                    {
                                        case 1:
                                            result.Append("unmilione");
                                            break;

                                        default:
                                            result.Append(convertNumberToReadableString(i));
                                            result.Append("milioni");

                                            break;
                                    }
                                    result.Append(convertNumberToReadableString(mod));
                                }
                                else
                                {
                                    if (num < 1000000000000)
                                    {
                                        mod = num % 1000000000;
                                        i = (num - mod) / 1000000000;
                                        switch (i)
                                        {
                                            case 1:
                                                result.Append("unmiliardo");
                                                break;

                                            default:
                                                result.Append(convertNumberToReadableString(i));
                                                result.Append("miliardi");

                                                break;
                                        }
                                        result.Append(convertNumberToReadableString(mod));
                                    }
                                }
                            }
                        }
                    }
                }
            }
            return result.ToString() ;
        }
    }

La funzione convertNumberToReadableString è stata presa da qui. Avendo questa classe tra le proprie utility, è possibile scrivere semplicemente: 

WordyFormatProviderITA f = new WordyFormatProviderITA();
var s = string.Format(f, "Il numero {0} in lettere è {0:W.4}", 9233234.8778);
Console.Write(s);

Che fornisce l’output:

Il numero 9233234,8778 in lettere è novemilioniduecentotrentatremiladuecentotrentaquattro/8778

Il formato è attivato dalla stringa W, nel caso di tipi reali può essere seguito dal parametro .n, dove n è il numero delle cifre dopo la virgola che si vuole stampare come /XX. Insomma è il formato di solito utilizzato sugli assegni.