public static string UrlEncode(string value)
{
if (string.IsNullOrEmpty(value))
return value;
int safeCount = 0;
int spaceCount = 0;
for (int i = 0; i < value.Length; i++)
{
char ch = value[i];
if (IsUrlSafeChar(ch))
{
safeCount++;
}
else if (ch == ' ')
{
spaceCount++;
}
}
int unexpandedCount = safeCount + spaceCount;
if (unexpandedCount == value.Length)
{
if (spaceCount != 0)
{
// Only spaces to encode
return value.Replace(' ', '+');
}
// Nothing to expand
return value;
}
int byteCount = Encoding.UTF8.GetByteCount(value);
int unsafeByteCount = byteCount - unexpandedCount;
int byteIndex = unsafeByteCount * 2;
// Instead of allocating one array of length `byteCount` to store
// the UTF-8 encoded bytes, and then a second array of length
// `3 * byteCount - 2 * unexpandedCount`
// to store the URL-encoded UTF-8 bytes, we allocate a single array of
// the latter and encode the data in place, saving the first allocation.
// We store the UTF-8 bytes to the end of this array, and then URL encode to the
// beginning of the array.
byte[] newBytes = new byte[byteCount + byteIndex];
Encoding.UTF8.GetBytes(value, 0, value.Length, newBytes, byteIndex);
GetEncodedBytes(newBytes, byteIndex, byteCount, newBytes);
return Encoding.UTF8.GetString(newBytes);
}