[C#] IFormatProvider для счетных существительных
От: PawnHunter  
Дата: 30.05.04 21:01
Оценка: 278 (18)
Класс NumeralsFormatter реализует интерфейс IFormatProvider.
Позволяет с помощью форматирующих строк строить грамматически правильные выражения, содержащие числовые значения. Позволяет форматировать числа в числительные. Поддерживает только русский и английский языки.
Короче, это для детей. (С)"Наследник Хадсакера"

Возможны два типа форматирования:
W — для выбора правильной формы существительного.
T — для построения числительного.

Из примеров все должно быть понятно.

NumeralsFormatter formatter = new NumeralsFormatter();
string s = String.Format(formatter, format, param1, param2, ...);


Дальше примеры того, каким может быть format, и каким может быть s в зависимости от параметров.

format = "Inbox: {0} {0:W;новое,новых} {0:W;сообщение,сообщения,сообщений}";

Inbox: 1 новое сообщение
Inbox: 2 новых сообщения
Inbox: 5 новых сообщений


Сокращенная форма:

format = "Inbox: {0} {0:W;нов(ое,ых)} {0:W;сообщени(е,я,й)}";

Inbox: 1 новое сообщение
Inbox: 2 новых сообщения
Inbox: 5 новых сообщений


Еще один пример:

format = "{0:W;Найден(а,о)} {0} {0:W;запис(ь,и,ей)}, {0:W;удовлетворяющ(ая,их)} запросу.";

Найдена 1 запись, удовлетворяющая запросу.
Найдено 5 записей, удовлетворяющих запросу.


Для форматирования числа в числительное используется символ T:

format = "{0:T}";

Одно
Тринадцать


После форматирующего символа можно через точку с запятой указать род числительного.
От регистра форматирующего символа зависит регистр первой буквы числительного:

format = "{0:t;f}";

одна
тринадцать


Еще несколько примеров:

format = "{0:T} {0:W;час(,а,ов)}.";

Два часа.
Десять часов.


format = "{0:T;M} {0:W;час(,а,ов)} {1:t;F} {1:W;минут(а,ы,)}.";

Два часа десять минут.
Двадцать один час одна минута.
Ноль часов ноль минут.


Сумма прписью:

format = "{0:T;M} {0:W;рубл(ь,я,ей)} {1:00} коп.";

Один рубль 12 коп.
Три рубля 05 коп.


Выбор языка числительных зависит от свойства NumeralsFormatter.CultureInfo.
По умолчанию используется CultureInfo текущего потока.
Можно явно передать нужный CultureInfo в конструктор NumeralsFormatter либо изменить значения свойства.

Переходим на английский:
formatter.CultureInfo = new CultureInfo("en-US");

format = "{0:T} {0:W;dollar(,s)} and {1:t} {1:W;cent(,s)}.";

One dollar and two cents.
One hundred and twenty-three thousand, four hundred and fifty-six dollars and seven cents.


Полученную строчку не стыдно и пользователю показать, а можно и синтезатору речи передать.
Если в системе установлен MS Text To Speech API, то можно на подобии английского языка послушать, который сейчас час.

format = "{0:T} {0:W;hour(,s)} and {1:t} {1:W;minute(,s)}.";
string text = String.Format(formatter, format, DateTime.Now.Hour, DateTime.Now.Minute);

SpVoiceClass voice = new SpVoiceClass();
voice.Speak(text, SpeechVoiceSpeakFlags.SVSFDefault);


Вообще-то MS Speech понимает цифры, и переводить их в текст не обязательно. Но если в языке числительные изменяются по родам (как в русском и многих других), то перевод в текст необходим.
Re: NumeralsFormatter.cs
От: PawnHunter  
Дата: 30.05.04 21:02
Оценка:
using System;
using System.Globalization;

namespace PawnHunter.Numerals
{
    /// <summary>
    /// Provides formatting of numerals and countable nouns.
    /// Russian and english languages are supported.
    /// </summary>
    /// <remarks>
    /// For english numerals the Thousands system of notation is used regardless of the subculture.
    /// See http://www.quinion.com/words/articles/numbers.htm for more information.
    /// </remarks>
    public sealed class NumeralsFormatter : IFormatProvider, ICustomFormatter
    {
        #region Fields

        private CultureInfo _cultureInfo;

        #endregion Fields

        #region Properties

        /// <summary>
        /// Gets or sets the culture for the formatter.
        /// </summary>
        public CultureInfo CultureInfo
        {
            get { return _cultureInfo; }
            set { _cultureInfo = value; }
        }

        #endregion Properties

        #region Constructors
        
        /// <summary>
        /// Initializes a new instance of the NumeralsFormatter class using the current thread's culture.
        /// </summary>
        public NumeralsFormatter()
        {
            _cultureInfo = CultureInfo.CurrentCulture;
        }

        /// <summary>
        /// Initializes a new instance of the NumeralsFormatter class using the specified culture.
        /// </summary>
        /// <param name="cultureInfo">CultureInfo representing the culture to be used by the formatter.</param>
        public NumeralsFormatter(CultureInfo cultureInfo)
        {
            _cultureInfo = cultureInfo;
        }
        
        #endregion Constructors
        
        #region Private methods

        /// <summary>
        /// Delegates numeral construction to language specific class
        /// </summary>
        private string FormatNumeral(string[] stringFormatParts, long arg)
        {
            bool uppercase = Char.IsUpper(stringFormatParts[0], 0);

            switch ( _cultureInfo.LCID & 0x00ff )
            {
                //
                // Add more languages here. ;)
                //

                case 0x09:
                    return English.ToString(arg, uppercase);
                
                case 0x19:
                    Gender gender;
                    
                    if (stringFormatParts.Length > 1)
                    {
                        switch (stringFormatParts[1].ToUpper())
                        {
                            case "F":
                                gender = Gender.Feminine;
                                break;
                            case "M":
                                gender = Gender.Masculine;
                                break;
                            case "N":
                                gender = Gender.Neutral;
                                break;
                            default:
                                throw new FormatException("Unknown gender.", new ArgumentOutOfRangeException());
                        }
                    }
                    else
                    {
                        gender = Gender.Neutral;
                    }

                    return Russian.ToString(arg, gender, uppercase);
                    
                default:
                    throw new FormatException(
                        String.Format("The '{0}' culture is not supported.", _cultureInfo.DisplayName),
                        new NotSupportedException());
            }
        }

        /// <summary>
        /// Parses formatting expression, 
        /// extracts and builds plural forms of a given word,
        /// delegates choise of the correct form to a Countable class instance.
        /// </summary>
        private string FormatCountable(string[] stringFormatParts, long arg)
        {
            string wordFormsString = stringFormatParts[stringFormatParts.Length - 1];
            string[] wordForms = wordFormsString.Split('(');

            string one, two, five;

            if (wordForms.Length == 2)
            {
                // looks like "<stem>(<flexions>)" format is used

                string stem = wordForms[0];
                string flectionsString = wordForms[1].Remove(wordForms[1].Length - 1, 1);
                string[] flexions = flectionsString.Split(',');

                one = stem + flexions[0];
                two = flexions.Length > 1 ? stem + flexions[1] : one;
                five = flexions.Length > 2 ? stem + flexions[2] : two;
            }
            else
            {
                // looks like "<singular>, <plural 2>, <plural 5>" format is used

                wordForms = wordFormsString.Split(',');
                one = wordForms[0];
                two = wordForms.Length > 1 ? wordForms[1] : one;
                five = wordForms.Length > 2 ? wordForms[2] : two;
            }

            // choose correct form for arg.
            Countable countable = new Countable(one, two, five);
            return countable[Math.Abs(arg)];
        }

        /// <summary>
        /// Performs default formatting.
        /// </summary>
        private string FormatUnknown(string format, object arg, IFormatProvider formatProvider)
        {
            IFormattable formattable = arg as IFormattable;

            if (formattable == null)
            {
                return arg.ToString();
            }
            else
            {
                return formattable.ToString(format, formatProvider);
            }
        }
    
        #region Helpers

        /// <summary>
        /// Gets a value indicating whether the type is an integral type.
        /// </summary>
        private bool IsIntegralType(Type type)
        {
            if (type == typeof(int)
                || type == typeof(uint)
                || type == typeof(long)
                || type == typeof(ulong)
                || type == typeof(short)
                || type == typeof(ushort)
                || type == typeof(byte)
                || type == typeof(sbyte)
                || type == typeof(char))
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        #endregion Helpers

        #endregion Private methods

        #region IFormatProvider implementation

        object IFormatProvider.GetFormat(Type formatType)
        {
            if (formatType == typeof(ICustomFormatter))
            {
                return this;
            }
            else
            {
                return CultureInfo.CurrentCulture.GetFormat(formatType);
            }
        }

        #endregion IFormatProvider implementation

        #region ICustomFormatter implementation

        /// <summary>
        /// Formats arg using the specified format.
        /// </summary>
        string ICustomFormatter.Format(string format, object arg, IFormatProvider formatProvider)
        {
            // NumeralsFormatter processes integral types only.
            if (format == null || !IsIntegralType(arg.GetType()))
            {
                return FormatUnknown(format, arg, formatProvider);
            }

            // The base type for NumeralsFormatter is long,
            // so check whether arg is within long's range
            if (arg.GetType() == typeof(ulong) && Convert.ToUInt64(arg) > long.MaxValue)
            {
                throw new FormatException("Argument is too large.", 
                    new ArgumentOutOfRangeException("arg", arg, 
                        String.Format("arg must be within -{0} ... {0} range.", long.MaxValue)));
            }

            string[] formatStringParts = format.Split(';');

            // NumeralsFormatter understands only 'T'('t') and 'W'('w') format specifiers.
            switch (formatStringParts[0].ToUpper())
            {
                case "T":
                    return FormatNumeral(formatStringParts, Convert.ToInt64(arg));
                case "W":
                    return FormatCountable(formatStringParts, Convert.ToInt64(arg));
                default:
                    return FormatUnknown(format, arg, formatProvider);
            }
        }

        #endregion ICustomFormatter
    }
}
Re: Countable.cs
От: PawnHunter  
Дата: 30.05.04 21:03
Оценка:
using System;

namespace PawnHunter.Numerals
{
    public enum Gender
    {
        Masculine,
        Feminine,
        Neutral
    }   

    public class Countable
    {
        #region Fields

        private string[] _forms = new string[3];
        private Gender _gender;

        #endregion Fields

        #region Properties

        public Gender Gender
        {
            get { return _gender; }
        }

        #endregion Properties

        #region Constructors

        public Countable(string one, string two, string five) :
            this(one, two, five, Gender.Neutral)
        {
        }

        public Countable(string one, string two, string five, Gender gender)
        {
            _forms[0] = one;
            _forms[1] = two;
            _forms[2] = five;

            _gender = gender;
        }

        #endregion Constructors

        #region Indexers

        public string this[long number]
        {
            get
            {
                number %= 100;
                
                if (number > 20)
                {
                    number %= 10;
                }

                if (number == 1)
                {
                    return _forms[0];
                }
                
                if (number > 1 && number < 5)
                {
                    return _forms[1];
                }
                
                return _forms[2];
            }
        }

        #endregion Indexers
    }
}
Re: Neutral.cs
От: PawnHunter  
Дата: 30.05.04 21:04
Оценка:
using System;

namespace PawnHunter.Numerals
{
    internal class Neutral
    {
        static internal long[] Ranks = new long[]
            {
                1000000000000000000,
                1000000000000000,
                1000000000000,
                1000000000,
                1000000,
                1000,
                1
            };
    }
}
Re: English.cs
От: PawnHunter  
Дата: 30.05.04 21:05
Оценка:
using System;
using System.Text;

namespace PawnHunter.Numerals
{
    public sealed class English
    {
        #region Fields
        
        private static string[] _ranks = new string[]
            {
                " quintillion", " quadrillion", " trillion", 
                " billion", " million", " thousand", ""
            };
        
        private static string[] _tens = new string[]
            {
                "", "ten", "twenty", "thirty", "forty", "fifty", 
                "sixty", "seventy", "eighty", "ninety" 
            };

        private static string[] _units = new string[]
            {
                "zero", "one", "two", "three", "four", "five", 
                "six", "seven", "eight", "nine", "ten", 
                "eleven", "twelve", "thirteen", "fourteen", "fifteen",
                "sixteen", "seventeen", "eighteen", "nineteen"
            };

        #endregion Fields

        #region Methods

        public static string ToString(long number)
        {
            return ToString(number, false);
        }

        public static string ToString(long number, bool uppercase)
        {
            if (number == 0)
            {
                if (uppercase)
                {
                    return Char.ToUpper(_units[0][0]) + _units[0].Remove(0, 1);
                }
                else
                {
                    return _units[0];
                }
            }

            bool isNegative = false;
            if (number < 0)
            {
                isNegative = true;
                number = Math.Abs(number);
            }

            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < Neutral.Ranks.Length; i++)
            {
                int rankValue = (int)(number / Neutral.Ranks[i]);
                number %= Neutral.Ranks[i];

                if (rankValue > 0)
                {
                    int hundreds = rankValue / 100;
                    int tens = rankValue / 10 % 10;
                    int units = rankValue % 10;

                    if (tens == 1)
                    {
                        tens = 0;
                        units = rankValue % 100;
                    }
        
                    if (sb.Length > 0)
                    {
                        if (hundreds > 0)
                            sb.Append(", ");
                        else if (tens + units > 0)
                            sb.Append(" and ");
                    }

                    if (hundreds > 0)
                    {
                        sb.Append(_units[hundreds]);
                        sb.Append(" hundred");
                        if ( tens + units > 0 )
                            sb.Append(" and ");
                    }
                    
                    if (tens > 0)
                    {
                        sb.Append(_tens[tens]);
                        if (units > 0)
                        {
                            sb.Append("-");
                        }
                    }
                    
                    if (units > 0)
                        sb.Append(_units[units]);

                    sb.Append(_ranks[i]);
                }
            }

            if (isNegative)
            {
                sb.Insert(0, "minus ");
            }

            if (uppercase)
            {
                sb[0] = Char.ToUpper(sb[0]);
            }

            return sb.ToString();
        }

        #endregion Methods
    }
}
Re: Russian.cs
От: PawnHunter  
Дата: 30.05.04 21:05
Оценка:
using System;
using System.Text;

namespace PawnHunter.Numerals
{
    public sealed class Russian
    {
        #region Fields

        private static Countable[] _ranks = new Countable[]
            {
                new Countable(" квинтильон", " квинтильона", " квинтильонов", Gender.Masculine),
                new Countable(" квадрильон", " квадрильона", " квадрильонов", Gender.Masculine),
                new Countable(" триллион", " триллиона", " триллионов", Gender.Masculine),
                new Countable(" миллиард", " миллиарда", " миллиардов", Gender.Masculine),
                new Countable(" миллион", " миллиона", " миллионов", Gender.Masculine),
                new Countable(" тысяча", " тысячи", " тысяч", Gender.Feminine),
                new Countable("", "", "")
            };

        private static string[] _hundreds = new string[]
            {
                "", "сто", "двести", "триста", "четыреста", "пятьсот", 
                "шестьсот", "семьсот", "восемьсот", "девятьсот"
            };

        private static string[] _tens = new string[]
            {
                "", "десять",  "двадцать", "тридцать", "сорок", "пятьдесят", 
                "шестьдесят", "семьдесят", "восемьдесят", "девяносто"
            };

        private static string[] _units = new string[]
            {
                "ноль", "один", "два", "три", "четыре", "пять", 
                "шесть", "семь", "восемь", "девять", "десять", "одиннадцать", 
                "двенадцать", "тринадцать", "четырнадцать", "пятнадцать",
                "шестнадцать", "семнадцать", "восемнадцать", "девятнадцать"
            };

        private static string[,] _gendered = new string[,]
            {
                { "один", "одна", "одно" },
                { "два",  "две",  "два" }
            };
        
        #endregion Fields

        #region Methods

        public static string ToString(long number, Gender gender)
        {
            return ToString(number, gender, false);
        }

        public static string ToString(long number, Gender gender, bool uppercase)
        {
            if (number == 0)
            {
                if (uppercase)
                {
                    return Char.ToUpper(_units[0][0]) + _units[0].Remove(0, 1);
                }
                else
                {
                    return _units[0];
                }
            }

            bool isNegative = false;
            if (number < 0)
            {
                isNegative = true;
                number = Math.Abs(number);
            }

            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < Neutral.Ranks.Length; i++ )
            {
                int rankValue = (int)(number / Neutral.Ranks[i]);
                number %= Neutral.Ranks[i];

                if (rankValue > 0)
                {
                    int hundreds = rankValue / 100;
                    int tens = rankValue / 10 % 10;
                    int units = rankValue % 10;

                    if (tens == 1)
                    {
                        tens = 0;
                        units = rankValue % 100;
                    }
        
                    if (sb.Length > 0)
                    {
                        sb.Append(" ");
                    }

                    if (hundreds > 0)
                    {
                        sb.Append(_hundreds[hundreds]);
                        if (tens + units > 0)
                        {
                            sb.Append(" ");
                        }
                    }
                    
                    if (tens > 0)
                    {
                        sb.Append(_tens[tens]);
                        if (units > 0)
                        {
                            sb.Append(" ");
                        }
                    }
                    
                    if (units > 0)
                    {
                        // mind the gender
                        if ( units < 3 ) 
                        {
                            int j = i == Neutral.Ranks.Length - 1 ? (int)gender : (int)_ranks[i].Gender;
                            sb.Append(_gendered[units-1, j]);
                        }
                        else
                        {
                            sb.Append(_units[units]);
                        }
                    }
                    sb.Append(_ranks[i][units]);
                }
            }

            if (isNegative)
            {
                sb.Insert(0, "минус ");
            }

            if (uppercase)
            {
                sb[0] = Char.ToUpper(sb[0]);
            }

            return sb.ToString();
        }

        #endregion Methods
    }
}
Re: Examples.cs
От: PawnHunter  
Дата: 30.05.04 21:07
Оценка:
using System;
using System.Diagnostics;
using System.Globalization;
using System.Threading;

// Microsoft Speech Object Library 5.0
// sapi.dll
using SpeechLib;

using PawnHunter.Numerals;

namespace PawnHunter
{
    /// <summary>
    /// Числительные и счетные существительныe.
    /// Примеры использования PawnHunter.Numerals.NumeralsFormatter.
    /// </summary>
    class NumeralsApplication
    {
        [STAThread]
        static void Main(string[] args)
        {
            Thread.CurrentThread.CurrentCulture = new CultureInfo("ru-RU");

            NumeralsFormatter formatter = new NumeralsFormatter();
            string format;

            format = "Inbox: {0} {0:W;новое,новых} {0:W;сообщение,сообщения,сообщений}";
            Console.WriteLine(String.Format(formatter, format, 1));
            Console.WriteLine(String.Format(formatter, format, 2));
            Console.WriteLine(String.Format(formatter, format, 5));
            Console.WriteLine();

            format = "Inbox: {0} {0:W;нов(ое,ых)} {0:W;сообщени(е,я,й)}";
            Console.WriteLine(String.Format(formatter, format, 1));
            Console.WriteLine(String.Format(formatter, format, 2));
            Console.WriteLine(String.Format(formatter, format, 5));
            Console.WriteLine();

            format = "{0:W;Найден(а,о)} {0} {0:W;запис(ь,и,ей)}, {0:W;удовлетворяющ(ая,их)} запросу.";
            Console.WriteLine(String.Format(formatter, format, 1));
            Console.WriteLine(String.Format(formatter, format, 5));
            Console.WriteLine();
        
            format = "{0:T}";
            Console.WriteLine(String.Format(formatter, format, 1));
            Console.WriteLine(String.Format(formatter, format, 13));
            Console.WriteLine();

            format = "{0:t;f}";
            Console.WriteLine(String.Format(formatter, format, 1));
            Console.WriteLine(String.Format(formatter, format, 13));
            Console.WriteLine();
        
            format = "{0:T;M} {0:W;час(,а,ов)}.";
            Console.WriteLine(String.Format(formatter, format, 2));
            Console.WriteLine(String.Format(formatter, format, 10));
            Console.WriteLine();

            format = "{0:T;M} {0:W;час(,а,ов)} {1:t;F} {1:W;минут(а,ы,)}.";
            Console.WriteLine(String.Format(formatter, format, 2, 10));
            Console.WriteLine(String.Format(formatter, format, 21, 1));
            Console.WriteLine(String.Format(formatter, format, 0, 0));
            Console.WriteLine();

            format = "{0:T;M} {0:W;рубл(ь,я,ей)} {1:00} коп.";
            Console.WriteLine(String.Format(formatter, format, 1, 12));
            Console.WriteLine(String.Format(formatter, format, 3, 5));
            Console.WriteLine(String.Format(formatter, format, -3, -5));
            Console.WriteLine();

            
            formatter.CultureInfo = new CultureInfo("en-US");

            format = "{0:T} {0:W;dollar(,s)} and {1:t} {1:W;cent(,s)}.";
            Console.WriteLine(String.Format(formatter, format, 1, 2));
            Console.WriteLine(String.Format(formatter, format, 123456, 7));
            Console.WriteLine();

            format = "{0:T} {0:W;hour(,s)} and {1:t} {1:W;minute(,s)}.";
            string text = String.Format(formatter, format,
                DateTime.Now.Hour, DateTime.Now.Minute);

            //SpVoiceClass voice = new SpVoiceClass();
            //voice.Speak(text, SpeechVoiceSpeakFlags.SVSFDefault);

            Console.Write("Press ENTER to exit.");
            Console.Read();
        }
    }
}
Добавил Ukrainian.cs
От: Andre Украина  
Дата: 30.05.04 22:55
Оценка: 16 (2)
Дописал поддержку для украинского языка. Для подключения необходимо будет внести несколько изменений в NumeralsFormatter.cs. Здесь не привожу, так как там по тексту все понятно

Ukrainian.cs
using System;
using System.Text;

namespace PawnHunter.Numerals
{
    public sealed class Ukrainian
    {
        #region Fields

        private static Countable[] _ranks = new Countable[]
            {
                new Countable(" квінтильйон", " квінтильйона", " квінтильйонів", Gender.Masculine),
                new Countable(" квадрильйон", " квадрильйона", " квадрильйонів", Gender.Masculine),
                new Countable(" трильйон", " трильйона", " трильйонів", Gender.Masculine),
                new Countable(" мільярд", " мільярда", " мільярдів", Gender.Masculine),
                new Countable(" мільйон", " мільйона", " мільйонів", Gender.Masculine),
                new Countable(" тисяча", " тисячі", " тисяч", Gender.Feminine),
                new Countable("", "", "")
            };

        private static string[] _hundreds = new string[]
            {
                "", "сто", "двісті", "триста", "чотириста", "п'ятсот", 
                "шістсот", "сімсот", "вісімсот", "дев'ятсот"
            };

        private static string[] _tens = new string[]
            {
                "", "десять",  "двадцять", "тридцять", "сорок", "п'ятдесят", 
                "шістдесят", "сімдесят", "вісімдесят", "дев'яносто"
            };

        private static string[] _units = new string[]
            {
                "нуль", "один", "два", "три", "чотири", "п'ять", 
                "шість", "сім", "вісім", "дев'ять", "десять", "одинадцять", 
                "дванадцять", "тринадцять", "чотирнадцять", "п'ятнадцять",
                "шістнадцять", "сімнадцять", "вісімнадцять", "дев'ятнадцять"
            };

        private static string[,] _gendered = new string[,]
            {
                { "один", "одна", "одне" },
                { "два",  "дві",  "двоє" }
            };
        
        #endregion Fields

        #region Methods

        public static string ToString(long number, Gender gender)
        {
            return ToString(number, gender, false);
        }

        public static string ToString(long number, Gender gender, bool uppercase)
        {
            if (number == 0)
            {
                if (uppercase)
                {
                    return Char.ToUpper(_units[0][0]) + _units[0].Remove(0, 1);
                }
                else
                {
                    return _units[0];
                }
            }

            bool isNegative = false;
            if (number < 0)
            {
                isNegative = true;
                number = Math.Abs(number);
            }

            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < Neutral.Ranks.Length; i++ )
            {
                int rankValue = (int)(number / Neutral.Ranks[i]);
                number %= Neutral.Ranks[i];

                if (rankValue > 0)
                {
                    int hundreds = rankValue / 100;
                    int tens = rankValue / 10 % 10;
                    int units = rankValue % 10;

                    if (tens == 1)
                    {
                        tens = 0;
                        units = rankValue % 100;
                    }
        
                    if (sb.Length > 0)
                    {
                        sb.Append(" ");
                    }

                    if (hundreds > 0)
                    {
                        sb.Append(_hundreds[hundreds]);
                        if (tens + units > 0)
                        {
                            sb.Append(" ");
                        }
                    }
                    
                    if (tens > 0)
                    {
                        sb.Append(_tens[tens]);
                        if (units > 0)
                        {
                            sb.Append(" ");
                        }
                    }
                    
                    if (units > 0)
                    {
                        // mind the gender
                        if ( units < 3 ) 
                        {
                            int j = i == Neutral.Ranks.Length - 1 ? (int)gender : (int)_ranks[i].Gender;
                            sb.Append(_gendered[units-1, j]);
                        }
                        else
                        {
                            sb.Append(_units[units]);
                        }
                    }
                    sb.Append(_ranks[i][units]);
                }
            }

            if (isNegative)
            {
                sb.Insert(0, "мінус ");
            }

            if (uppercase)
            {
                sb[0] = Char.ToUpper(sb[0]);
            }

            return sb.ToString();
        }

        #endregion Methods
    }
}
... << RSDN@Home 1.1.4 beta 1 >> :: Vopli Vidoplyasova — Vesna
Я бы изменил мир — но Бог не даёт исходников...
а может выложить одним архивом?
От: SiAVoL Россия  
Дата: 31.05.04 06:34
Оценка:
исключительно для удобства, а то выдирать файлы из нескольких сообщения как-то не очень
... << RSDN@Home 1.1.4 beta 1 >>
Re: а может выложить одним архивом?
От: PawnHunter  
Дата: 31.05.04 07:38
Оценка:
Здравствуйте, SiAVoL, Вы писали:

SAV>исключительно для удобства, а то выдирать файлы из нескольких сообщения как-то не очень

А как?
Re[2]: а может выложить одним архивом?
От: SiAVoL Россия  
Дата: 31.05.04 08:05
Оценка:
Здравствуйте, PawnHunter, Вы писали:

PH>Здравствуйте, SiAVoL, Вы писали:


SAV>>исключительно для удобства, а то выдирать файлы из нескольких сообщения как-то не очень

PH>А как?
Зайти в свой профиль, ткнуть на "файлы", а там уже сам разберешься
... << RSDN@Home 1.1.4 beta 1 >>
Re: Все файлы в архиве Numerals.zip
От: PawnHunter  
Дата: 31.05.04 20:16
Оценка:
Numerals.zip
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.