Path.Combine for URLs?

前端 未结 30 2595
不思量自难忘°
不思量自难忘° 2020-11-22 14:28

Path.Combine is handy, but is there a similar function in the .NET framework for URLs?

I\'m looking for syntax like this:

Url.Combine(\"http://MyUrl.         


        
30条回答
  •  天命终不由人
    2020-11-22 15:14

    If you don't want to have a dependency like Flurl, you can use its source code:

        /// 
        /// Basically a Path.Combine for URLs. Ensures exactly one '/' separates each segment,
        /// and exactly on '&' separates each query parameter.
        /// URL-encodes illegal characters but not reserved characters.
        /// 
        /// URL parts to combine.
        public static string Combine(params string[] parts) {
            if (parts == null)
                throw new ArgumentNullException(nameof(parts));
    
            string result = "";
            bool inQuery = false, inFragment = false;
    
            string CombineEnsureSingleSeparator(string a, string b, char separator) {
                if (string.IsNullOrEmpty(a)) return b;
                if (string.IsNullOrEmpty(b)) return a;
                return a.TrimEnd(separator) + separator + b.TrimStart(separator);
            }
    
            foreach (var part in parts) {
                if (string.IsNullOrEmpty(part))
                    continue;
    
                if (result.EndsWith("?") || part.StartsWith("?"))
                    result = CombineEnsureSingleSeparator(result, part, '?');
                else if (result.EndsWith("#") || part.StartsWith("#"))
                    result = CombineEnsureSingleSeparator(result, part, '#');
                else if (inFragment)
                    result += part;
                else if (inQuery)
                    result = CombineEnsureSingleSeparator(result, part, '&');
                else
                    result = CombineEnsureSingleSeparator(result, part, '/');
    
                if (part.Contains("#")) {
                    inQuery = false;
                    inFragment = true;
                }
                else if (!inFragment && part.Contains("?")) {
                    inQuery = true;
                }
            }
            return EncodeIllegalCharacters(result);
        }
    
        /// 
        /// URL-encodes characters in a string that are neither reserved nor unreserved. Avoids encoding reserved characters such as '/' and '?'. Avoids encoding '%' if it begins a %-hex-hex sequence (i.e. avoids double-encoding).
        /// 
        /// The string to encode.
        /// If true, spaces will be encoded as + signs. Otherwise, they'll be encoded as %20.
        /// The encoded URL.
        public static string EncodeIllegalCharacters(string s, bool encodeSpaceAsPlus = false) {
            if (string.IsNullOrEmpty(s))
                return s;
    
            if (encodeSpaceAsPlus)
                s = s.Replace(" ", "+");
    
            // Uri.EscapeUriString mostly does what we want - encodes illegal characters only - but it has a quirk
            // in that % isn't illegal if it's the start of a %-encoded sequence https://stackoverflow.com/a/47636037/62600
    
            // no % characters, so avoid the regex overhead
            if (!s.Contains("%"))
                return Uri.EscapeUriString(s);
    
            // pick out all %-hex-hex matches and avoid double-encoding 
            return Regex.Replace(s, "(.*?)((%[0-9A-Fa-f]{2})|$)", c => {
                var a = c.Groups[1].Value; // group 1 is a sequence with no %-encoding - encode illegal characters
                var b = c.Groups[2].Value; // group 2 is a valid 3-character %-encoded sequence - leave it alone!
                return Uri.EscapeUriString(a) + b;
            });
        }
    

提交回复
热议问题