<commit_before>﻿namespace Nancy.Routing
{
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Globalization;
    using System.Linq;
    using System.Text.RegularExpressions;
    using Nancy.Extensions;

    public class RouteResolver : IRouteResolver
    {
        public IRoute GetRoute(IRequest request, IEnumerable<RouteDescription> descriptions)
        {
            var matchingRoutes =
                from description in descriptions
                let matcher = BuildRegexMatcher(description)
                let result = matcher.Match(request.Uri)
                where result.Success
                select new
                {
                    Groups = result.Groups,
                    Description = description
                };

            var selected = matchingRoutes
                .OrderByDescending(x => GetSegmentCount(x.Description))
                .FirstOrDefault();

            return selected != null ?
                new Route(selected.Description.GetModuleQualifiedPath(), GetParameters(selected.Description, selected.Groups), selected.Description.Action) : 
                new NoMatchingRouteFoundRoute(request.Uri);
        }

        private static RouteParameters GetParameters(RouteDescription description, GroupCollection groups)
        {
            var segments =
                new ReadOnlyCollection<string>(
                    description.Path.Split(new[] { "/" },
                    StringSplitOptions.RemoveEmptyEntries).ToList());

            var parameters =
                from segment in segments
                where segment.IsParameterized()
                select segment.GetParameterName();

            dynamic data =
                new RouteParameters();

            foreach (var parameter in parameters)
            {
                data[parameter] = groups[parameter].Value;
            }

            return data;
        }

        private static Regex BuildRegexMatcher(RouteDescription description)
        {
            var segments =
                description.GetModuleQualifiedPath().Split(new[] {"/"}, StringSplitOptions.RemoveEmptyEntries);

            var parameterizedSegments =
                GetParameterizedSegments(segments);

            var pattern =
                string.Concat(@"^/", string.Join("/", parameterizedSegments), @"$");

            return new Regex(pattern, RegexOptions.IgnoreCase);
        }

        private static IEnumerable<string> GetParameterizedSegments(IEnumerable<string> segments)
        {
            foreach (var segment in segments)
            {
                var current = segment;
                if (current.IsParameterized())
                {
                    var replacement =
                        string.Format(CultureInfo.InvariantCulture, @"(?<{0}>[/A-Z0-9_-]*)", segment.GetParameterName());

                    current = segment.Replace(segment, replacement);<commit_msg>Added support for passing in . characters in route parameters<commit_after>﻿namespace Nancy.Routing
{
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Globalization;
    using System.Linq;
    using System.Text.RegularExpressions;
    using Nancy.Extensions;

    public class RouteResolver : IRouteResolver
    {
        public IRoute GetRoute(IRequest request, IEnumerable<RouteDescription> descriptions)
        {
            var matchingRoutes =
                from description in descriptions
                let matcher = BuildRegexMatcher(description)
                let result = matcher.Match(request.Uri)
                where result.Success
                select new
                {
                    Groups = result.Groups,
                    Description = description
                };

            var selected = matchingRoutes
                .OrderByDescending(x => GetSegmentCount(x.Description))
                .FirstOrDefault();

            return selected != null ?
                new Route(selected.Description.GetModuleQualifiedPath(), GetParameters(selected.Description, selected.Groups), selected.Description.Action) : 
                new NoMatchingRouteFoundRoute(request.Uri);
        }

        private static RouteParameters GetParameters(RouteDescription description, GroupCollection groups)
        {
            var segments =
                new ReadOnlyCollection<string>(
                    description.Path.Split(new[] { "/" },
                    StringSplitOptions.RemoveEmptyEntries).ToList());

            var parameters =
                from segment in segments
                where segment.IsParameterized()
                select segment.GetParameterName();

            dynamic data =
                new RouteParameters();

            foreach (var parameter in parameters)
            {
                data[parameter] = groups[parameter].Value;
            }

            return data;
        }

        private static Regex BuildRegexMatcher(RouteDescription description)
        {
            var segments =
                description.GetModuleQualifiedPath().Split(new[] {"/"}, StringSplitOptions.RemoveEmptyEntries);

            var parameterizedSegments =
                GetParameterizedSegments(segments);

            var pattern =
                string.Concat(@"^/", string.Join("/", parameterizedSegments), @"$");

            return new Regex(pattern, RegexOptions.IgnoreCase);
        }

        private static IEnumerable<string> GetParameterizedSegments(IEnumerable<string> segments)
        {
            foreach (var segment in segments)
            {
                var current = segment;
                if (current.IsParameterized())
                {
                    var replacement =
                        string.Format(CultureInfo.InvariantCulture, @"(?<{0}>[/A-Z0-9._-]*)", segment.GetParameterName());

                    current = segment.Replace(segment, replacement);
{'fraction_non_alphanumeric': 0.08010636529832142, 'fraction_numerical': 0.0009971746717633372, 'mean_word_length': 1.7835337650323775, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3933346', 'n_tokens_mistral': 1367, 'n_tokens_neox': 1264, 'n_words': 291}