[successivo] [precedente] [inizio] [fine] [indice generale] [violazione GPL] [translators] [docinfo] [indice analitico] [volume] [parte]


Capitolo 354.   Trasformazione in lettere

Nell'ambito della realizzazione di applicativi gestionali, capitano frequentemente problemi di conversione di numeri interi in una qualche forma alfabetica. In questo capitolo vengono mostrati degli algoritmi molto semplici per risolvere questo tipo di problemi.

354.1   Da numero a sequenza alfabetica pura

Esiste un tipo di numerazione in cui si utilizzano solo le lettere dell'alfabeto, dalla «a» alla «z», senza accenti o altri simboli speciali, senza distinguere tra maiuscole e minuscole. In generale, i simboli da «a» a «z» consentono di rappresentare valori da 1 a 26, dove lo zero è escluso. Per rappresentare valori superiori, si possono accoppiare più lettere, ma il calcolo non è banale, proprio perché manca lo zero.

Attraverso la pseudocodifica introdotta nel capitolo 282, si può descrivere una funzione che calcoli la stringa corrispondente a un numero intero positivo, maggiore di zero. Per prima cosa, occorre definire una sotto funzione che sia in grado di trasformare un numero intero, compreso tra 1 e 26 nella lettera alfabetica corrispondente; ciò si ottiene abbastanza facilmente, attraverso la verifica di più condizioni in cascata. Il vero problema, purtroppo, sta nel costruire una stringa composta da più lettere, quando si vuole rappresentare un valore superiore a 26. Non essendoci lo zero, diventa difficile fare i calcoli. Se si parte dal presupposto che il numero da convertire non possa essere superiore a 702, si sa con certezza che servono al massimo due lettere alfabetiche (perché la stringa «ZZ» corrisponderebbe proprio al numero 702); in tal caso, è sufficiente dividere il numero per 26, dove la parte intera rappresenta la prima lettera, mentre il resto rappresenta la seconda. Tuttavia, se la divisione non dà resto, la stringa corretta è quella precedente. Per esempio, il numero 53 corrisponde alla stringa «BA», perché 53/26 = 2 con un resto di 1. Nello stesso modo, però, 52 si traduce nella stringa «AZ», perché 53/26 = 2, ma non c'è resto, pertanto, «B » diventa «AZ».

La pseudocodifica seguente riepiloga il concetto in modo semplificato, dove, a seconda delle esigenze, la conversione è sempre limitata a un valore massimo. Le omissioni sono parti di codice facilmente intuibili.

INTEGER_TO_ALPHABET (N)

    ALPHABET_DIGIT (DIGIT)
        IF DIGIT = 0
            THEN
                RETURN ""
        ELSE IF DIGIT = 1
            THEN
                RETURN "A"
        ELSE IF DIGIT = 2
            THEN
                RETURN "B"
        ...
        ...
        ELSE IF DIGIT = 26
            THEN
                RETURN "Z"
        ELSE
            RETURN "##ERROR##"
        FI
    END ALPHABET_DIGIT

    IF N <= 0
        THEN
            RETURN "##ERROR##";
    ELSE IF N <= 26
        THEN
            RETURN ALPHABET_DIGIT (N)
    ELSE IF N <= 52
        THEN
            N := N - 52
            RETURN "A" ALPHABET_DIGIT (N)
    ELSE IF N <= 78
        THEN
            N := N - 78
            RETURN "B" ALPHABET_DIGIT (N)
    ...
    ...
    ELSE IF N <= 702
        THEN
            N := N - 702
            RETURN "Z" ALPHABET_DIGIT (N)
    ELSE IF N <= 728
        THEN
            N := N - 728
            RETURN "AA" ALPHABET_DIGIT (N)
    ELSE IF N <= 754
        THEN
            N := N - 754
            RETURN "AB" ALPHABET_DIGIT (N)
    ...
    ...
    ELSE
        RETURN "##ERROR##"
    END IF
END INTEGER_TO_ALPHABET

354.2   Da numero a numero romano

La conversione di un numero intero positivo in una stringa che rappresenta un numero romano, ha un discreto livello di difficoltà, perché la numerazione romana non prevede lo zero, perché la tecnica prevede la somma e la sottrazione di simboli (a seconda della posizione) e poi perché diventa difficile indicare valori multipli delle migliaia.

Per prima cosa è necessario conoscere il valore associato ai simboli elementari:

Simbolo Valore corrispondente
I 1
V 5
X 10
L 50
C 100
D 500
M 1 000

Un simbolo posto alla destra di un altro simbolo con un valore maggiore o uguale di questo, viene sommato; al contrario, un simbolo posto alla sinistra di un altro simbolo con un valore maggiore o uguale di questo, viene sottratto. Per esempio, «VI» equivale a 5+1, mentre «IV» equivale a 5-1. Esistono comunque anche altri vincoli, per evitare di creare numeri difficili da interpretare a causa di una complessità di calcolo eccessiva.

Per risolvere il problema con un algoritmo relativamente semplice, si può scomporre il valore di partenza in fasce: unità, decine, centinaia e migliaia (la conversione di valori superiori genererebbe soltanto una serie lunghissima di «M» che risulta poi troppo difficile da leggere).

INTEGER_TO_ROMAN (N)

    LOCAL DIGIT_1 INTEGER
    LOCAL DIGIT_2 INTEGER
    LOCAL DIGIT_3 INTEGER
    LOCAL DIGIT_4 INTEGER

    DIGIT_1 := 0
    DIGIT_2 := 0
    DIGIT_3 := 0
    DIGIT_4 := 0

    DIGIT_1_TO_ROMAN (DIGIT)
        IF DIGIT = 0
            THEN
                RETURN ""
        ELSE IF DIGIT = 1
            THEN
                RETURN "I"
        ELSE IF DIGIT = 2
            THEN
                RETURN "II"
        ELSE IF DIGIT = 3
            THEN
                RETURN "III"
        ELSE IF DIGIT = 4
            THEN
                RETURN "IV"
        ELSE IF DIGIT = 5
            THEN
                RETURN "V"
        ELSE IF DIGIT = 6
            THEN
                RETURN "VI"
        ELSE IF DIGIT = 7
            THEN
                RETURN "VII"
        ELSE IF DIGIT = 8
            THEN
                RETURN "VIII"
        ELSE IF DIGIT = 9
            THEN
                RETURN "IX"
        END IF
    END DIGIT_1_TO_ROMAN

    DIGIT_2_TO_ROMAN (DIGIT)
        IF DIGIT = 0
            THEN
                RETURN ""
        ELSE IF DIGIT = 1
            THEN
                RETURN "X"
        ELSE IF DIGIT = 2
            THEN
                RETURN "XX"
        ELSE IF DIGIT = 3
            THEN
                RETURN "XXX"
        ELSE IF DIGIT = 4
            THEN
                RETURN "XL"
        ELSE IF DIGIT = 5
            THEN
                RETURN "L"
        ELSE IF DIGIT = 6
            THEN
                RETURN "LX"
        ELSE IF DIGIT = 6
            THEN
                RETURN "LXX"
        ELSE IF DIGIT = 8
            THEN
                RETURN "LXXX"
        ELSE IF DIGIT = 9
            THEN
                RETURN "XC"
        END IF
    END DIGIT_2_TO_ROMAN

    DIGIT_3_TO_ROMAN (DIGIT)
        IF DIGIT = 0
            THEN
                RETURN ""
        ELSE IF DIGIT = 1
            THEN
                RETURN "C"
        ELSE IF DIGIT = 2
            THEN
                RETURN "CC"
        ELSE IF DIGIT = 3
            THEN
                RETURN "CCC"
        ELSE IF DIGIT = 4
            THEN
                RETURN "CD"
        ELSE IF DIGIT = 5
            THEN
                RETURN "D"
        ELSE IF DIGIT = 6
            THEN
                RETURN "DC"
        ELSE IF DIGIT = 7
            THEN
                RETURN "DCC"
        ELSE IF DIGIT = 8
            THEN
                RETURN "DCCC"
        ELSE IF DIGIT = 9
            THEN
                RETURN "CM"
        END IF
    END DIGIT_3_TO_ROMAN

    DIGIT_4_TO_ROMAN (DIGIT)
        IF DIGIT = 0
            THEN
                RETURN ""
        ELSE IF DIGIT = 1
            THEN
                RETURN "M"
        ELSE IF DIGIT = 2
            THEN
                RETURN "MM"
        ELSE IF DIGIT = 3
            THEN
                RETURN "MMM"
        ELSE IF DIGIT = 4
            THEN
                RETURN "MMMM"
        ELSE IF DIGIT = 5
            THEN
                RETURN "MMMMM"
        ELSE IF DIGIT = 6
            THEN
                RETURN "MMMMMM"
        ELSE IF DIGIT = 7
            THEN
                RETURN "MMMMMMM"
        ELSE IF DIGIT = 8
            THEN
                RETURN "MMMMMMMM"
        ELSE IF DIGIT = 9
            THEN
                RETURN "MMMMMMMMM"
        END IF
    END DIGIT_4_TO_ROMAN

    DIGIT_4 := int (N/1000)
    N := N - (DIGIT_4 * 1000)

    DIGIT_3 := int (N/100)
    N := N - (DIGIT_3 * 100)

    DIGIT_2 := int (N/10)
    N := N - (DIGIT_2 * 10)

    DIGIT_1 := N

    RETURN DIGIT_4_TO_ROMAN (DIGIT_4)
           DIGIT_3_TO_ROMAN (DIGIT_3)
           DIGIT_2_TO_ROMAN (DIGIT_2)
           DIGIT_1_TO_ROMAN (DIGIT_2)

END INTEGER_TO_ROMAN

Come si vede, dopo aver scomposto il valore in quattro fasce, si utilizzano quattro funzioni distinte per ottenere la porzione di stringa che traduce il valore relativo. L'istruzione RETURN finale intende concatenare tutte le stringhe risultanti.

354.3   Da numero a lettere, nel senso verbale

Quando si trasforma un numero in lettere, per esempio quando si vuole trasformare 123 in «centoventitre», l'algoritmo di conversione deve tenere conto delle convenzioni linguistiche e non esiste una soluzione generale per tutte le lingue.

Per quanto riguarda la lingua italiana, esistono nomi diversi fino al 19, poi ci sono delle particolarità per i plurali o i singolari. La pseudocodifica seguente risolve il problema in una sola funzione ricorsiva. Le omissioni dovrebbero essere sufficientemente intuitive.

INTEGER_TO_ITALIAN (N)

    LOCAL X INTEGER
    LOCAL Y INTEGER

    IF N = 0
        THEN
            RETURN ""
    ELSE IF N = 1
        THEN
            RETURN "UNO"
    ELSE IF N = 2
        THEN
            RETURN "DUE"
    ELSE IF N = 3
        THEN
            RETURN "TRE"
    ELSE IF N = 4
        THEN
            RETURN "QUATTRO"
    ELSE IF N = 5
        THEN
            RETURN "CINQUE"
    ELSE IF N = 6
        THEN
            RETURN "SEI"
    ELSE IF N = 7
        THEN
            RETURN "SETTE"
    ELSE IF N = 8
        THEN
            RETURN "OTTO"
    ELSE IF N = 9
        THEN
            RETURN "NOVE"
    ELSE IF N = 10
        THEN
            RETURN "DIECI"
    ELSE IF N = 11
        THEN
            RETURN "UNDICI"
    ELSE IF N = 12
        THEN
            RETURN "DODICI"
    ELSE IF N = 13
        THEN
            RETURN "TREDICI"
    ELSE IF N = 14
        THEN
            RETURN "QUATTORDICI"
    ELSE IF N = 15
        THEN
            RETURN "QUINDICI"
    ELSE IF N = 16
        THEN
            RETURN "SEDICI"
    ELSE IF N = 17
        THEN
            RETURN "DICIASSETTE"
    ELSE IF N = 18
        THEN
            RETURN "DICIOTTO"
    ELSE IF N = 19
        THEN
            RETURN "DICIANNOVE"
    ELSE IF N = 20
        THEN
            RETURN "VENTI"
    ELSE IF N = 21
        THEN
            RETURN "VENTUNO"
    ELSE IF (N >= 22) AND (N <= 29)
        THEN
            RETURN "VENTI" INTEGER_TO_ITALIAN (N-20)
    ELSE IF N = 30
        THEN
            RETURN "TRENTA"
    ELSE IF N = 31
        THEN
            RETURN "TRENTUNO"
    ELSE IF (N >= 32) AND (N <= 39)
        THEN
            RETURN "TRENTA" INTEGER_TO_ITALIAN (N-30)
    ...
    ...
    ELSE IF N = 90
        THEN
            RETURN "NOVANTA"
    ELSE IF N = 91
        THEN
            RETURN "NOVANTUNO"
    ELSE IF (N >= 92) AND (N <= 99)
        THEN
            RETURN "NOVANTA" INTEGER_TO_ITALIAN (N-90)
    ELSE IF (N >= 100) AND (N <= 199)
        THEN
            RETURN "CENTO" INTEGER_TO_ITALIAN (N-100)
    ELSE IF (N >= 200) AND (N <= 999)
        THEN
            X := int (N / 100)
            Y := N - (X * 100)
            RETURN INTEGER_TO_ITALIAN (X)
                   "CENTO"
                   INTEGER_TO_ITALIAN (Y)
    ELSE IF (N >= 1000) AND (N <= 1999)
        THEN
            RETURN "MILLE" INTEGER_TO_ITALIAN (N-1000)
    ELSE IF (N >= 2000) AND (N <= 999999)
        THEN
            X := int (N / 1000)
            Y := N - (X * 1000)
            RETURN INTEGER_TO_ITALIAN (X)
                   "MILA"
                   INTEGER_TO_ITALIAN (Y)
    ELSE IF (N >= 1000000) AND (N <= 1999999)
        THEN
            RETURN "UNMILIONE" INTEGER_TO_ITALIAN (N-1000000)
    ELSE IF (N >= 2000000) AND (N <= 999999999)
        THEN
            X := int (N / 1000000)
            Y := N - (X * 1000000)
            RETURN INTEGER_TO_ITALIAN (X)
                   "MILIONI"
                   INTEGER_TO_ITALIAN (Y)
    ELSE IF (N >= 1000000000) AND (N <= 1999999999)
        THEN
            RETURN "UNMILIARDO" INTEGER_TO_ITALIAN (N-1000000000)
    ELSE IF (N >= 2000000000) AND (N <= 999999999999)
        THEN
            X := int (N / 1000000000)
            Y := N - (X * 1000000000)
            RETURN INTEGER_TO_ITALIAN (X)
                   "MILIARDI"
                   INTEGER_TO_ITALIAN (Y)
    ELSE
        "##ERROR##"
    END IF
END INTEGER_TO_ITALIAN
Appunti di informatica libera 2003.01.01 --- Copyright © 2000-2003 Daniele Giacomini -- daniele @ swlibero.org

Dovrebbe essere possibile fare riferimento a questa pagina anche con il nome trasformazione_in_lettere.html

[successivo] [precedente] [inizio] [fine] [indice generale] [violazione GPL] [translators] [docinfo] [indice analitico]