Пример #1
0
        private static TextLiteralType PeekSymbol(Char aC, Int32 aMaskDepth, CConvertOptions aPCO)
        {
            switch (aC)
            {
            //   Цифры.
            case '0':
            case '1':
            case '2':
            case '3':
            case '4':
            case '5':
            case '6':
            case '7':
            case '8':
            case '9':
            {
                return(TextLiteralType.Number);
            }
            //break;

            //   Пробелы и табуляция.
            case ' ':
            case '\t':
            {
                return(TextLiteralType.Whitespace);
            }
            //break;

            //   Иные символы для уточнения.
            default:
            {
            }
            break;
            }


            if ((aMaskDepth < aPCO.SeparatorMask.Length) && (aC == aPCO.SeparatorMask[aMaskDepth]))
            {
                return(TextLiteralType.Separator);
            }


            if ((aMaskDepth < aPCO.JointMask.Length) && (aC == aPCO.JointMask[aMaskDepth]))
            {
                return(TextLiteralType.Joint);
            }


            return(TextLiteralType.Error);
        }
Пример #2
0
        private static Literal PeekLiteral
        (
            String aData,
            Int32 aStartIndex,
            CConvertOptions aPCO
        )
        {
            if (aData.Length <= 0)
            {
                throw new ArgumentException("Empty input text", "Data");
            }
            if (aStartIndex >= aData.Length)
            {
                throw new ArgumentException("Index is out of range.", "StartIndex");
            }


            Literal Result = Literal.InvalidLiteral;

            Int32 PeekI = aStartIndex;
            Int32 MaskI = 0;

            TextLiteralType Mode = PeekSymbol(aData[PeekI], MaskI, aPCO);

            Result.MatchType = Mode;
            Result.MatchCount++;
            PeekI++;

            while ((PeekI < aData.Length) && (PeekI < aStartIndex + aPCO.MaxElementLength))
            {
                Char            C       = aData[PeekI];
                TextLiteralType NewMode = PeekSymbol(C, MaskI, aPCO);

                if (Mode != NewMode)
                {
                    break;
                }

                Result.MatchCount++;
                PeekI++;
                MaskI++;
            }

            string NumberData = aData.Substring(aStartIndex, Result.MatchCount);
            int    Number;

            Result.MatchNumber = int.TryParse(NumberData, out Number) ? Number : 0;

            return(Result);
        }
        public static int[] Convert
        (
            string aData,
            string aSeparator = CConvertOptions.DefaultSeparator,
            string aJoint     = CConvertOptions.DefaultJoint
        )
        {
            const int DataNumericBase = 10;

            var ResultList = new List <int> ();


            if (aData.Length <= 0)
            {
                return(ResultList.ToArray());
            }

            if (aSeparator.Length <= 0)
            {
                throw new ArgumentException("", "Separator");
            }
            if (aJoint.Length <= 0)
            {
                throw new ArgumentException("", "Joint");
            }
            if (!CConvertOptions.Validate(aSeparator, aJoint))
            {
                throw new ArgumentException("", "Joint, Separator");
            }


            Char      C;
            ParseMode PrevMode = ParseMode.Undefined;

            int I = -1;

            int ParseSeparatorIndex = 0;
            int ParseJointIndex     = 0;
            int ParseNumber         = 0;
            int ParseNumberIndex    = 0;
            int ParseRangeLowIndex  = 0;

            int  SavedRangeStart = 0;
            bool SavedRangeMode  = false;

            int LastValue = int.MinValue;


            //===  Две инлайн функции для повторяющегося кода. ====================================
            Action inline_Add = delegate()
            {
                int Value = ParseNumber;

                if (Value < 0)
                {
                    throw new ArgumentException("Invalid elements in input data (invalid value).", "Data");
                }

                if (Value <= LastValue)
                {
                    throw new ArgumentException(String.Format("The input set contains invalid data at index [{0}]. The value is less or equal to previous element.", I), "Data");
                }

                ResultList.Add(Value);
                LastValue = Value;
            };
            //=====================================================================================
            Action inline_AddRange = delegate()
            {
                int RStart = SavedRangeStart + 1;
                int RCount = ParseNumber - SavedRangeStart;

                if ((RStart < 0) || (RCount <= 0))
                {
                    throw new ArgumentException("Invalid elements in input data (invalid range).", "Data");
                }

                if (RStart <= LastValue)
                {
                    throw new ArgumentException(String.Format("The input set contains invalid data range from [{0}] to [{1}]. The value is less or equal to previous element.", ParseRangeLowIndex, I), "Data");
                }

                ResultList.AddRange(Enumerable.Range(RStart, RCount));
                LastValue = RStart + RCount - 1;

                SavedRangeStart = 0;
                SavedRangeMode  = false;
            };

            //=====================================================================================


            for (I = 0; I < aData.Length; I++)
            {
                C = aData[I];


                //   Выбираем режим работы.
                ParseMode Mode = ParseMode.Error;

                if (Char.IsWhiteSpace(C))
                {
                    Mode = ParseMode.Whitespace;
                }
                else if ((ParseSeparatorIndex < aSeparator.Length) && (C == aSeparator[ParseSeparatorIndex]))
                {
                    ParseSeparatorIndex++;
                    Mode = ParseMode.Separator;
                }
                else if ((ParseJointIndex < aJoint.Length) && (C == aJoint[ParseJointIndex]))
                {
                    ParseJointIndex++;
                    Mode = ParseMode.Joint;
                }
                //   Если мы не вошли в режим разделителя или связки,
                //   и обнаружен символ, отвечающий за цифры.
                else if (Char.IsNumber(C)) // (ParseJointIndex == 0) && (ParseSeparatorIndex == 0) &&
                {
                    //   Повышаем разряд числа и прибавляем новую часть.
                    ParseNumber = (ParseNumber * DataNumericBase) + (int)Char.GetNumericValue(C);
                    ParseNumberIndex++;
                    Mode = ParseMode.Number;
                }


                if (Mode == ParseMode.Error)
                {
                    throw new ArgumentException("Invalid input data.", "Data");
                }


                //  Режим данных изменился = это означает поступление нового элемента
                if (PrevMode != Mode)
                {
                    if ((PrevMode == ParseMode.Joint) && (ParseJointIndex > 0))
                    {
                        if (ParseJointIndex == aJoint.Length)
                        {
                            //   Обнаружена связка двух чисел (диапазон).

                            SavedRangeMode = true;

                            ParseJointIndex = 0;
                        }
                        else if (ParseJointIndex > aJoint.Length)
                        {
                            throw new ArgumentException(String.Format("Invalid joint sequence detected at pos [{0}]", I), "Data");
                        }
                    }
                    else if ((PrevMode == ParseMode.Separator) && (ParseSeparatorIndex > 0))
                    {
                        if (ParseSeparatorIndex == aSeparator.Length)
                        {
                            //   Обнаружен разделитель между элементами.

                            ParseSeparatorIndex = 0;
                        }
                        else if (ParseSeparatorIndex > aSeparator.Length)
                        {
                            throw new ArgumentException(String.Format("Invalid separator sequence detected at pos [{0}]", I), "Data");
                        }
                    }
                    else if ((PrevMode == ParseMode.Number) && (ParseNumberIndex > 0))
                    {
                        //   Обнаружено начало или продолжение числа.

                        if (SavedRangeMode)
                        {
                            inline_AddRange();
                        }
                        else
                        {
                            inline_Add();
                        }

                        SavedRangeStart = ParseNumber;

                        ParseNumber      = 0;
                        ParseNumberIndex = 0;
                    }


                    PrevMode = Mode;
                }
            }


            if (SavedRangeMode)
            {
                inline_AddRange();
            }
            else
            {
                inline_Add();
            }


            return(ResultList.ToArray());
        }
Пример #4
0
 int[] INumericConverterEx.Convert(string aData, CConvertOptions aOptions)
 {
     return(Convert(aData, aOptions.SeparatorMask, aOptions.JointMask));
 }
Пример #5
0
        public static int[] Convert
        (
            string aData,
            string aSeparator = CConvertOptions.DefaultSeparator,
            string aJoint     = CConvertOptions.DefaultJoint
        )
        {
            //   TODO: Временный отладочный вывод.
            Console.Write("\n");

            List <int> Result = new List <int> (1024);

            Literal Prev = Literal.InvalidLiteral;
            Literal Next = Literal.InvalidLiteral;

            Literal LastNumeric = Literal.InvalidLiteral;

            Literal         ParseResult;
            CConvertOptions PCO = new CConvertOptions {
                SeparatorMask = aSeparator, JointMask = aJoint
            };


            int I = 0;

            Prev.MatchType = TextLiteralType.Separator;


            for (; I < aData.Length;)
            {
                ParseElement(aData, ref I, out ParseResult, PCO);

                if (ParseResult.IsWhiteSpace())
                {
                    //  Пробелы просто пропускаем. В любом количестве.
                    continue;
                }

                Next = ParseResult;

                //   Если обнаруженные элементы совпадают по типу, значит
                //   мы можем уже сказать, что в данных ошибка (например, два числа следуют
                //   друг за другом, без иных возможных разделителей).
                if (Next.MatchType == Prev.MatchType)
                {
                    throw new ArgumentException("Invalid elements in input data (duplicate data).", "Data");
                }

                switch (Next.MatchType)
                {
                case TextLiteralType.Number:
                {
                    if (Prev.MatchType == TextLiteralType.Joint)
                    {
                        //   Связка перед числом => Новый диапазон значений.

                        int From  = LastNumeric.MatchNumber + 1;
                        int Count = Next.MatchNumber - LastNumeric.MatchNumber;

                        if (Count <= 0)
                        {
                            throw new ArgumentException("Invalid elements in input data (invalid range).", "Data");
                        }

                        Result.AddRange(Enumerable.Range(From, Count));
                    }
                    else if (Prev.MatchType == TextLiteralType.Separator)
                    {
                        //   Разделитель перед числом => Добавляем число.
                        Result.Add(Next.MatchNumber);
                    }
                    else if (Prev.MatchType == TextLiteralType.Uncertain)
                    {
                        //   Первый неопределенный элемент (пустышка) = Все в порядке.
                    }
                }
                break;

                case TextLiteralType.Separator:
                {
                    if (Prev.MatchType == TextLiteralType.Number)
                    {
                        //   Разделитель групп перед числовым литералом = Все в порядке.
                    }
                    else
                    {
                        //   Выходим с ошибкой парсера.
                        goto default;
                    }
                }
                break;

                case TextLiteralType.Joint:
                {
                    if (Prev.MatchType == TextLiteralType.Number)
                    {
                        //   Связка перед числовым литералом = Все в порядке.
                    }
                    else
                    {
                        //   Выходим с ошибкой парсера.
                        goto default;
                    }
                }
                break;

                default:
                {
                    throw new ArgumentException("Error element in input data.", "Data");
                }
                    //break;
                }


                if (ParseResult.MatchType == TextLiteralType.Number)
                {
                    LastNumeric = ParseResult;
                }

                Prev = Next;
            }


            return(Result.ToArray());
        }
Пример #6
0
        private static void ParseElement(String aData, ref int rParseIndex, out Literal rParseResult, CConvertOptions aPCO)
        {
            rParseResult = PeekLiteral(aData, rParseIndex, aPCO);

            //   TODO: Временный отладочный вывод.
            Console.ForegroundColor = rParseResult.GetColorFromType();
            Console.WriteLine(String.Format
                              (
                                  "{0}:{1} = [{2}]",
                                  /* 0 */ rParseResult.MatchType.ToString(),
                                  /* 1 */ rParseResult.MatchCount,
                                  /* 2 */ aData.Substring(rParseIndex, rParseResult.MatchCount)
                              ));
            Console.ResetColor();

            rParseIndex += rParseResult.MatchCount;
        }