244 lines
5.6 KiB
C#
244 lines
5.6 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Collections.Immutable;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
|
|
namespace Roslyn.Utilities;
|
|
|
|
internal static class StringExtensions
|
|
{
|
|
private static ImmutableArray<string> s_lazyNumerals;
|
|
|
|
private static readonly Func<char, char> s_toLower = char.ToLower;
|
|
|
|
private static readonly Func<char, char> s_toUpper = char.ToUpper;
|
|
|
|
private const string AttributeSuffix = "Attribute";
|
|
|
|
internal static string GetNumeral(int number)
|
|
{
|
|
ImmutableArray<string> value = s_lazyNumerals;
|
|
if (value.IsDefault)
|
|
{
|
|
value = ImmutableArray.Create(new string[10] { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" });
|
|
ImmutableInterlocked.InterlockedInitialize(ref s_lazyNumerals, value);
|
|
}
|
|
if (number >= value.Length)
|
|
{
|
|
return number.ToString();
|
|
}
|
|
return value[number];
|
|
}
|
|
|
|
public static string Join(this IEnumerable<string?> source, string separator)
|
|
{
|
|
if (source == null)
|
|
{
|
|
throw new ArgumentNullException("source");
|
|
}
|
|
if (separator == null)
|
|
{
|
|
throw new ArgumentNullException("separator");
|
|
}
|
|
return string.Join(separator, source);
|
|
}
|
|
|
|
public static bool LooksLikeInterfaceName(this string name)
|
|
{
|
|
if (name.Length >= 3 && name[0] == 'I' && char.IsUpper(name[1]))
|
|
{
|
|
return char.IsLower(name[2]);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public static bool LooksLikeTypeParameterName(this string name)
|
|
{
|
|
if (name.Length >= 3 && name[0] == 'T' && char.IsUpper(name[1]))
|
|
{
|
|
return char.IsLower(name[2]);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
[return: NotNullIfNotNull("shortName")]
|
|
public static string? ToPascalCase(this string? shortName, bool trimLeadingTypePrefix = true)
|
|
{
|
|
return shortName.ConvertCase(trimLeadingTypePrefix, s_toUpper);
|
|
}
|
|
|
|
[return: NotNullIfNotNull("shortName")]
|
|
public static string? ToCamelCase(this string? shortName, bool trimLeadingTypePrefix = true)
|
|
{
|
|
return shortName.ConvertCase(trimLeadingTypePrefix, s_toLower);
|
|
}
|
|
|
|
[return: NotNullIfNotNull("shortName")]
|
|
private static string? ConvertCase(this string? shortName, bool trimLeadingTypePrefix, Func<char, char> convert)
|
|
{
|
|
if (!RoslynString.IsNullOrEmpty(shortName))
|
|
{
|
|
if (trimLeadingTypePrefix && (shortName.LooksLikeInterfaceName() || shortName.LooksLikeTypeParameterName()))
|
|
{
|
|
return convert(shortName[1]) + shortName.Substring(2);
|
|
}
|
|
if (convert(shortName[0]) != shortName[0])
|
|
{
|
|
return convert(shortName[0]) + shortName.Substring(1);
|
|
}
|
|
}
|
|
return shortName;
|
|
}
|
|
|
|
internal static bool IsValidClrTypeName([NotNullWhen(true)] this string? name)
|
|
{
|
|
if (!RoslynString.IsNullOrEmpty(name))
|
|
{
|
|
return name.IndexOf('\0') == -1;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
internal static bool IsValidClrNamespaceName([NotNullWhen(true)] this string? name)
|
|
{
|
|
if (RoslynString.IsNullOrEmpty(name))
|
|
{
|
|
return false;
|
|
}
|
|
char c = '.';
|
|
foreach (char c2 in name)
|
|
{
|
|
if (c2 == '\0' || (c2 == '.' && c == '.'))
|
|
{
|
|
return false;
|
|
}
|
|
c = c2;
|
|
}
|
|
return c != '.';
|
|
}
|
|
|
|
internal static string GetWithSingleAttributeSuffix(this string name, bool isCaseSensitive)
|
|
{
|
|
string text = name;
|
|
while ((text = text.GetWithoutAttributeSuffix(isCaseSensitive)) != null)
|
|
{
|
|
name = text;
|
|
}
|
|
return name + "Attribute";
|
|
}
|
|
|
|
internal static bool TryGetWithoutAttributeSuffix(this string name, [NotNullWhen(true)] out string? result)
|
|
{
|
|
return name.TryGetWithoutAttributeSuffix(isCaseSensitive: true, out result);
|
|
}
|
|
|
|
internal static string? GetWithoutAttributeSuffix(this string name, bool isCaseSensitive)
|
|
{
|
|
if (!name.TryGetWithoutAttributeSuffix(isCaseSensitive, out string result))
|
|
{
|
|
return null;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
internal static bool TryGetWithoutAttributeSuffix(this string name, bool isCaseSensitive, [NotNullWhen(true)] out string? result)
|
|
{
|
|
if (name.HasAttributeSuffix(isCaseSensitive))
|
|
{
|
|
result = name.Substring(0, name.Length - "Attribute".Length);
|
|
return true;
|
|
}
|
|
result = null;
|
|
return false;
|
|
}
|
|
|
|
internal static bool HasAttributeSuffix(this string name, bool isCaseSensitive)
|
|
{
|
|
StringComparison comparisonType = (isCaseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase);
|
|
if (name.Length > "Attribute".Length)
|
|
{
|
|
return name.EndsWith("Attribute", comparisonType);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
internal static bool IsValidUnicodeString(this string str)
|
|
{
|
|
int num = 0;
|
|
while (num < str.Length)
|
|
{
|
|
char c = str[num++];
|
|
if (char.IsHighSurrogate(c))
|
|
{
|
|
if (num >= str.Length || !char.IsLowSurrogate(str[num]))
|
|
{
|
|
return false;
|
|
}
|
|
num++;
|
|
}
|
|
else if (char.IsLowSurrogate(c))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
internal static string Unquote(this string arg)
|
|
{
|
|
bool quoted;
|
|
return arg.Unquote(out quoted);
|
|
}
|
|
|
|
internal static string Unquote(this string arg, out bool quoted)
|
|
{
|
|
if (arg.Length > 1 && arg[0] == '"' && arg[arg.Length - 1] == '"')
|
|
{
|
|
quoted = true;
|
|
return arg.Substring(1, arg.Length - 2);
|
|
}
|
|
quoted = false;
|
|
return arg;
|
|
}
|
|
|
|
internal static char First(this string arg)
|
|
{
|
|
return arg[0];
|
|
}
|
|
|
|
internal static char Last(this string arg)
|
|
{
|
|
return arg[arg.Length - 1];
|
|
}
|
|
|
|
internal static bool All(this string arg, Predicate<char> predicate)
|
|
{
|
|
foreach (char obj in arg)
|
|
{
|
|
if (!predicate(obj))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public static int GetCaseInsensitivePrefixLength(this string string1, string string2)
|
|
{
|
|
int i;
|
|
for (i = 0; i < string1.Length && i < string2.Length && char.ToUpper(string1[i]) == char.ToUpper(string2[i]); i++)
|
|
{
|
|
}
|
|
return i;
|
|
}
|
|
|
|
public static int GetCaseSensitivePrefixLength(this string string1, string string2)
|
|
{
|
|
int i;
|
|
for (i = 0; i < string1.Length && i < string2.Length && string1[i] == string2[i]; i++)
|
|
{
|
|
}
|
|
return i;
|
|
}
|
|
}
|