Godot.Sharp.Extended/StringExtensionMethods.cs
2025-09-26 03:13:44 -05:00

305 lines
No EOL
11 KiB
C#

using System.Globalization;
using System.Runtime.CompilerServices;
namespace Godot.Sharp.Extended.Generators;
public static class StringExtensionMethods
{
public static string ToPascalCase(this string value)
{
int newIndex = 0;
bool insertSeparator = true;
UnicodeCategory previous;
UnicodeCategory current = UnicodeCategory.OtherSymbol;
char[] newString = new char[value.Length + CalculateSpanSizeForPascalOrCamelCase(value)];
for (int i = 0; i < value.Length; i++)
{
previous = current;
current = char.GetUnicodeCategory(value[i]);
insertSeparator =
(previous != current && (current is UnicodeCategory.UppercaseLetter ||
current is UnicodeCategory.DecimalDigitNumber)) || insertSeparator;
if (!IsSpecialCharacter(current))
{
newString[newIndex] = insertSeparator
? char.ToUpperInvariant(value[i])
: char.ToLowerInvariant(value[i]);
insertSeparator = false;
newIndex++;
}
}
return new(newString);
}
public static string ToCamelCase(this string value)
{
int newIndex = 0;
bool insertSeparator = false;
bool isFirstCharacter = true;
UnicodeCategory previous;
UnicodeCategory current = UnicodeCategory.OtherSymbol;
char[] newString = new char[value.Length + CalculateSpanSizeForPascalOrCamelCase(value)];
for (int i = 0; i < value.Length; i++)
{
previous = current;
current = char.GetUnicodeCategory(value[i]);
insertSeparator =
(previous != current && (current is UnicodeCategory.UppercaseLetter ||
current is UnicodeCategory.DecimalDigitNumber)) || insertSeparator;
if (!IsSpecialCharacter(current))
{
newString[newIndex] = insertSeparator && !isFirstCharacter
? char.ToUpperInvariant(value[i])
: char.ToLowerInvariant(value[i]);
isFirstCharacter = false;
insertSeparator = false;
newIndex++;
}
}
return new(newString);
}
public static string ToUnderscoreCamelCase(this string value)
{
int newIndex = 1;
bool insertSeparator = false;
bool isFirstCharacter = true;
UnicodeCategory previous;
UnicodeCategory current = UnicodeCategory.OtherSymbol;
char[] newString = new char[value.Length + CalculateSpanSizeForPascalOrCamelCase(value) + 1];
newString[0] = '_';
for (int i = 1; i < value.Length; i++)
{
previous = current;
current = char.GetUnicodeCategory(value[i]);
insertSeparator =
(previous != current && (current is UnicodeCategory.UppercaseLetter ||
current is UnicodeCategory.DecimalDigitNumber)) || insertSeparator;
if (!IsSpecialCharacter(current))
{
newString[newIndex] = insertSeparator && !isFirstCharacter
? char.ToUpperInvariant(value[i])
: char.ToLowerInvariant(value[i]);
isFirstCharacter = false;
insertSeparator = false;
newIndex++;
}
}
return new(newString);
}
public static string ToKebabCase(this string value)
{
int newIndex = 0;
bool insertSeparator = true;
bool isFirstCharacter = true;
UnicodeCategory previous;
UnicodeCategory current = UnicodeCategory.OtherSymbol;
char[] newString = new char[value.Length + CalculateSpanSizeForKebabOrSnakeCase(value)];
for (int i = 0; i < value.Length; i++)
{
previous = current;
current = char.GetUnicodeCategory(value[i]);
insertSeparator =
(previous != current && (current is UnicodeCategory.UppercaseLetter ||
current is UnicodeCategory.DecimalDigitNumber)) || insertSeparator;
if (!IsSpecialCharacter(current))
{
if (insertSeparator && !isFirstCharacter)
{
newString[newIndex] = '-';
newIndex++;
}
newString[newIndex] = char.ToLowerInvariant(value[i]);
isFirstCharacter = false;
insertSeparator = false;
newIndex++;
}
}
return new(newString);
}
public static string ToSnakeCase(this string value)
{
int newIndex = 0;
bool insertSeparator = true;
bool isFirstCharacter = true;
UnicodeCategory previous;
UnicodeCategory current = UnicodeCategory.OtherSymbol;
char[] newString = new char[value.Length + CalculateSpanSizeForKebabOrSnakeCase(value)];
for (int i = 0; i < value.Length; i++)
{
previous = current;
current = char.GetUnicodeCategory(value[i]);
insertSeparator =
(previous != current && (current is UnicodeCategory.UppercaseLetter ||
current is UnicodeCategory.DecimalDigitNumber)) || insertSeparator;
if (!IsSpecialCharacter(current))
{
if (insertSeparator && !isFirstCharacter)
{
newString[newIndex] = '_';
newIndex++;
}
newString[newIndex] = char.ToLowerInvariant(value[i]);
isFirstCharacter = false;
insertSeparator = false;
newIndex++;
}
}
return new(newString);
}
public static string ToMacroCase(this string value)
{
int newIndex = 0;
bool insertSeparator = true;
bool isFirstCharacter = true;
UnicodeCategory previous;
UnicodeCategory current = UnicodeCategory.OtherSymbol;
char[] newString = new char[value.Length + CalculateSpanSizeForKebabOrSnakeCase(value)];
for (int i = 0; i < value.Length; i++)
{
previous = current;
current = char.GetUnicodeCategory(value[i]);
insertSeparator =
(previous != current && (current is UnicodeCategory.UppercaseLetter ||
current is UnicodeCategory.DecimalDigitNumber)) || insertSeparator;
if (!IsSpecialCharacter(current))
{
if (insertSeparator && !isFirstCharacter)
{
newString[newIndex] = '_';
newIndex++;
}
newString[newIndex] = char.ToUpperInvariant(value[i]);
isFirstCharacter = false;
insertSeparator = false;
newIndex++;
}
}
return new(newString);
}
public static string ToTrainCase(this string value)
{
int newIndex = 0;
bool insertSeparator = true;
bool isFirstCharacter = true;
UnicodeCategory previous;
UnicodeCategory current = UnicodeCategory.OtherSymbol;
char[] newString = new char[value.Length + CalculateSpanSizeForKebabOrSnakeCase(value)];
for (int i = 0; i < value.Length; i++)
{
previous = current;
current = char.GetUnicodeCategory(value[i]);
insertSeparator =
(previous != current && (current is UnicodeCategory.UppercaseLetter ||
current is UnicodeCategory.DecimalDigitNumber)) || insertSeparator;
if (!IsSpecialCharacter(current))
{
if (insertSeparator && !isFirstCharacter)
{
newString[newIndex] = '-';
newIndex++;
}
newString[newIndex] = insertSeparator
? char.ToUpperInvariant(value[i])
: char.ToLowerInvariant(value[i]);
isFirstCharacter = false;
insertSeparator = false;
newIndex++;
}
}
return new(newString);
}
public static string ToTitleCase(this string value)
{
int newIndex = 0;
bool insertSeparator = true;
bool isFirstCharacter = true;
UnicodeCategory previous;
UnicodeCategory current = UnicodeCategory.OtherSymbol;
char[] newString = new char[value.Length + CalculateSpanSizeForKebabOrSnakeCase(value)];
for (int i = 0; i < value.Length; i++)
{
previous = current;
current = char.GetUnicodeCategory(value[i]);
insertSeparator =
(previous != current && (current is UnicodeCategory.UppercaseLetter ||
current is UnicodeCategory.DecimalDigitNumber)) || insertSeparator;
if (!IsSpecialCharacter(current))
{
if (insertSeparator && !isFirstCharacter)
{
newString[newIndex] = ' ';
newIndex++;
}
newString[newIndex] = insertSeparator
? char.ToUpperInvariant(value[i])
: char.ToLowerInvariant(value[i]);
isFirstCharacter = false;
insertSeparator = false;
newIndex++;
}
}
return new(newString);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int CalculateSpanSizeForKebabOrSnakeCase(string text)
{
UnicodeCategory previous = char.GetUnicodeCategory(text[0]);
UnicodeCategory current;
int skips = IsSpecialCharacter(previous) ? 1 : 0;
int divs = 0;
for (int i = 1; i < text.Length; i++)
{
current = char.GetUnicodeCategory(text[i]);
skips += IsSpecialCharacter(current) ? 1 : 0;
divs += previous != current && (current is UnicodeCategory.UppercaseLetter ||
current is UnicodeCategory.DecimalDigitNumber)
? 1
: 0;
previous = current;
}
return divs - skips;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int CalculateSpanSizeForPascalOrCamelCase(string text)
{
UnicodeCategory current;
int skips = 0;
for (int i = 0; i < text.Length - 1; i++)
{
current = char.GetUnicodeCategory(text[i]);
skips -= IsSpecialCharacter(current) ? 1 : 0;
}
return skips;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static bool IsSpecialCharacter(UnicodeCategory category)
{
return category is not UnicodeCategory.UppercaseLetter
and not UnicodeCategory.LowercaseLetter
and not UnicodeCategory.DecimalDigitNumber;
}
}