public void CharacterClassMergingAdjacentNegatedTest()
        {
            var target = CharacterClass.Negate(CharacterClass.Union(new CharacterClass('a'), new CharacterClass('b'), new CharacterClass('c'), new CharacterClass('d'), new CharacterClass('e')));

            Assert.AreEqual(1, target.excludedRanges.Count);
            Assert.AreEqual(0, target.includedRanges.Count);
        }
        public void IntersectANegatedSetTest()
        {
            // gives just the consonants
            //[a-z&&[^aeiou]]

            var target = CharacterClass.Intersect(
                new CharacterClass('a', 'z'),
                CharacterClass.Negate(
                    CharacterClass.Union(
                        new CharacterClass('a'),
                        new CharacterClass('e'),
                        new CharacterClass('i'),
                        new CharacterClass('o'),
                        new CharacterClass('u')
                        )
                    )
                );

            var vowels     = "aeiou";
            var consonants = "bcdfghjklmnpqrstvwxyz";

            foreach (var character in vowels)
            {
                Assert.AreEqual(false, target.Contains(character));
            }

            foreach (var character in consonants)
            {
                Assert.AreEqual(true, target.Contains(character));
            }
        }
        private CharacterClass MultiCharacterClass()
        {
            bool negative = false;

            // are we dealing with a negated character class?
            if (Peek() == '^')
            {
                negative = true;
                Consume('^');
            }

            var output = new CharacterClass();

            // keep going until we find the last closing bracket
            while (More() && Peek() != ']')
            {
                // parse a single charclass out
                var single = SingleCharacterClass();

                // union them together
                output = CharacterClass.Union(output, single);

                // have we got a intersection or substraction?
                while (More() && PeekIsAny('&', '-'))
                {
                    switch (Peek())
                    {
                    case '&':
                        // intersection
                        Consume('&');
                        Consume('&');
                        var and = IntersectionWithClass();
                        output = CharacterClass.Intersect(output, and);
                        break;

                    case '-':
                        // subtraction
                        Consume('-');
                        var subtract = MultiCharacterClass();
                        output = CharacterClass.Subtract(output, subtract);
                        break;
                    }
                }
            }

            if (negative)
            {
                output = CharacterClass.Negate(output);
            }

            return(output);
        }
        public void CharacterClassToStringTest()
        {
            // gives just the consonants
            //[a-z&&[^aeiuo]]

            var target = CharacterClass.Intersect(
                new CharacterClass('a', 'z'),
                CharacterClass.Negate(
                    CharacterClass.Union(
                        new CharacterClass('a'),
                        new CharacterClass('e'),
                        new CharacterClass('i'),
                        new CharacterClass('o'),
                        new CharacterClass('u')
                        )
                    )
                );

            Assert.AreEqual("[a-z&&[^aeiou]]", target.ToString());
        }
        public void NegateRangeContainsTest(char c, bool expected)
        {
            var target = CharacterClass.Negate(new CharacterClass('b', 'd'));

            Assert.AreEqual(expected, target.Contains(c));
        }
        private CharacterClass EscapedSpecialCharacter(char character)
        {
            switch (character)
            {
            // we are escaping a backspash
            case '\\':
                return(new CharacterClass('\\'));

            case 'd':     // digits
            case 'D':     // NON digits
            {
                var charClass = new CharacterClass('0', '9');

                if (character == 'D')
                {
                    charClass = CharacterClass.Negate(charClass);
                }

                return(charClass);
            }

            case 'w':     // alpha numerics and dash
            case 'W':     // NON alpha numerics and dash
            {
                var charClass = CharacterClass.Union(
                    new CharacterClass('A', 'Z'),
                    new CharacterClass('a', 'z'),
                    new CharacterClass('0', '9'),
                    new CharacterClass('-')
                    );

                if (character == 'W')
                {
                    charClass = CharacterClass.Negate(charClass);
                }

                return(charClass);
            }

            case 's':     // whitespace
            case 'S':     // NON whitespace
            {
                var charClass = CharacterClass.Union(
                    new CharacterClass(' '),
                    new CharacterClass('\t'),
                    new CharacterClass('\r'),
                    new CharacterClass('\n'),
                    new CharacterClass('\f')
                    );

                if (character == 'S')
                {
                    charClass = CharacterClass.Negate(charClass);
                }

                return(charClass);
            }

            case 'u':     // unicode escape sequence
                return(new CharacterClass(UnicodeEscapeSequence()));

            default:
                throw new UnexpectedCharacterParseException(string.Format("Unexpected escape sequence {0}", character));
            }
        }