mirror of
https://gitlab.com/Kwoth/nadekobot.git
synced 2025-09-11 17:58:26 -04:00
Lots more stuff
This commit is contained in:
@@ -37,7 +37,9 @@ public static class EnumerableExtensions
|
||||
/// </returns>
|
||||
public static string Join<T>(this IEnumerable<T> data, string separator, Func<T, string>? func = null)
|
||||
=> string.Join(separator, data.Select(func ?? (x => x?.ToString() ?? string.Empty)));
|
||||
|
||||
|
||||
|
||||
// todo have 2 different shuffles
|
||||
/// <summary>
|
||||
/// Randomize element order by performing the Fisher-Yates shuffle
|
||||
/// </summary>
|
||||
|
139
src/Nadeko.Common/Extensions/StringExtensions.cs
Normal file
139
src/Nadeko.Common/Extensions/StringExtensions.cs
Normal file
@@ -0,0 +1,139 @@
|
||||
using NadekoBot.Common.Yml;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using Humanizer;
|
||||
using Nadeko.Common;
|
||||
|
||||
namespace NadekoBot.Extensions;
|
||||
|
||||
public static class StringExtensions
|
||||
{
|
||||
private static readonly HashSet<char> _lettersAndDigits = new(Enumerable.Range(48, 10)
|
||||
.Concat(Enumerable.Range(65, 26))
|
||||
.Concat(Enumerable.Range(97, 26))
|
||||
.Select(x => (char)x));
|
||||
|
||||
private static readonly Regex _filterRegex = new(@"discord(?:\.gg|\.io|\.me|\.li|(?:app)?\.com\/invite)\/(\w+)",
|
||||
RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
private static readonly Regex _codePointRegex =
|
||||
new(@"(\\U(?<code>[a-zA-Z0-9]{8})|\\u(?<code>[a-zA-Z0-9]{4})|\\x(?<code>[a-zA-Z0-9]{2}))",
|
||||
RegexOptions.Compiled);
|
||||
|
||||
public static string PadBoth(this string str, int length)
|
||||
{
|
||||
var spaces = length - str.Length;
|
||||
var padLeft = (spaces / 2) + str.Length;
|
||||
return str.PadLeft(padLeft, ' ').PadRight(length, ' ');
|
||||
}
|
||||
|
||||
public static string StripHtml(this string input)
|
||||
=> Regex.Replace(input, "<.*?>", string.Empty);
|
||||
|
||||
public static string? TrimTo(this string? str, int maxLength, bool hideDots = false)
|
||||
=> hideDots ? str?.Truncate(maxLength, string.Empty) : str?.Truncate(maxLength);
|
||||
|
||||
public static string ToTitleCase(this string str)
|
||||
{
|
||||
var tokens = str.Split(new[] { " " }, StringSplitOptions.RemoveEmptyEntries);
|
||||
for (var i = 0; i < tokens.Length; i++)
|
||||
{
|
||||
var token = tokens[i];
|
||||
tokens[i] = token[..1].ToUpperInvariant() + token[1..];
|
||||
}
|
||||
|
||||
return tokens.Join(" ").Replace(" Of ", " of ").Replace(" The ", " the ");
|
||||
}
|
||||
|
||||
//http://www.dotnetperls.com/levenshtein
|
||||
public static int LevenshteinDistance(this string s, string t)
|
||||
{
|
||||
var n = s.Length;
|
||||
var m = t.Length;
|
||||
var d = new int[n + 1, m + 1];
|
||||
|
||||
// Step 1
|
||||
if (n == 0)
|
||||
return m;
|
||||
|
||||
if (m == 0)
|
||||
return n;
|
||||
|
||||
// Step 2
|
||||
for (var i = 0; i <= n; d[i, 0] = i++)
|
||||
{
|
||||
}
|
||||
|
||||
for (var j = 0; j <= m; d[0, j] = j++)
|
||||
{
|
||||
}
|
||||
|
||||
// Step 3
|
||||
for (var i = 1; i <= n; i++)
|
||||
//Step 4
|
||||
for (var j = 1; j <= m; j++)
|
||||
{
|
||||
// Step 5
|
||||
var cost = t[j - 1] == s[i - 1] ? 0 : 1;
|
||||
|
||||
// Step 6
|
||||
d[i, j] = Math.Min(Math.Min(d[i - 1, j] + 1, d[i, j - 1] + 1), d[i - 1, j - 1] + cost);
|
||||
}
|
||||
|
||||
// Step 7
|
||||
return d[n, m];
|
||||
}
|
||||
|
||||
public static async Task<Stream> ToStream(this string str)
|
||||
{
|
||||
var ms = new MemoryStream();
|
||||
var sw = new StreamWriter(ms);
|
||||
await sw.WriteAsync(str);
|
||||
await sw.FlushAsync();
|
||||
ms.Position = 0;
|
||||
return ms;
|
||||
}
|
||||
|
||||
public static bool IsDiscordInvite(this string str)
|
||||
=> _filterRegex.IsMatch(str);
|
||||
|
||||
public static string Unmention(this string str)
|
||||
=> str.Replace("@", "ම", StringComparison.InvariantCulture);
|
||||
|
||||
public static string SanitizeMentions(this string str, bool sanitizeRoleMentions = false)
|
||||
{
|
||||
str = str.Replace("@everyone", "@everyοne", StringComparison.InvariantCultureIgnoreCase)
|
||||
.Replace("@here", "@һere", StringComparison.InvariantCultureIgnoreCase);
|
||||
if (sanitizeRoleMentions)
|
||||
str = str.SanitizeRoleMentions();
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
public static string SanitizeRoleMentions(this string str)
|
||||
=> str.Replace("<@&", "<ම&", StringComparison.InvariantCultureIgnoreCase);
|
||||
|
||||
public static string SanitizeAllMentions(this string str)
|
||||
=> str.SanitizeMentions().SanitizeRoleMentions();
|
||||
|
||||
public static string ToBase64(this string plainText)
|
||||
{
|
||||
var plainTextBytes = Encoding.UTF8.GetBytes(plainText);
|
||||
return Convert.ToBase64String(plainTextBytes);
|
||||
}
|
||||
|
||||
public static string GetInitials(this string txt, string glue = "")
|
||||
=> txt.Split(' ').Select(x => x.FirstOrDefault()).Join(glue);
|
||||
|
||||
public static bool IsAlphaNumeric(this string txt)
|
||||
=> txt.All(c => _lettersAndDigits.Contains(c));
|
||||
|
||||
public static string UnescapeUnicodeCodePoints(this string input)
|
||||
=> _codePointRegex.Replace(input,
|
||||
me =>
|
||||
{
|
||||
var str = me.Groups["code"].Value;
|
||||
var newString = YamlHelper.UnescapeUnicodeCodePoint(str);
|
||||
return newString;
|
||||
});
|
||||
}
|
@@ -7,6 +7,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Humanizer.Core" Version="2.14.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="7.0.0" />
|
||||
<PackageReference Include="NonBlocking" Version="2.1.1" />
|
||||
<PackageReference Include="OneOf" Version="3.0.223" />
|
||||
|
48
src/Nadeko.Common/YamlHelper.cs
Normal file
48
src/Nadeko.Common/YamlHelper.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
#nullable disable
|
||||
namespace NadekoBot.Common.Yml;
|
||||
|
||||
public static class YamlHelper
|
||||
{
|
||||
// https://github.com/aaubry/YamlDotNet/blob/0f4cc205e8b2dd8ef6589d96de32bf608a687c6f/YamlDotNet/Core/Scanner.cs#L1687
|
||||
/// <summary>
|
||||
/// This is modified code from yamldotnet's repo which handles parsing unicode code points
|
||||
/// it is needed as yamldotnet doesn't support unescaped unicode characters
|
||||
/// </summary>
|
||||
/// <param name="point">Unicode code point</param>
|
||||
/// <returns>Actual character</returns>
|
||||
public static string UnescapeUnicodeCodePoint(this string point)
|
||||
{
|
||||
var character = 0;
|
||||
|
||||
// Scan the character value.
|
||||
|
||||
foreach (var c in point)
|
||||
{
|
||||
if (!IsHex(c))
|
||||
return point;
|
||||
|
||||
character = (character << 4) + AsHex(c);
|
||||
}
|
||||
|
||||
// Check the value and write the character.
|
||||
|
||||
if (character is (>= 0xD800 and <= 0xDFFF) or > 0x10FFFF)
|
||||
return point;
|
||||
|
||||
return char.ConvertFromUtf32(character);
|
||||
}
|
||||
|
||||
public static bool IsHex(char c)
|
||||
=> c is (>= '0' and <= '9') or (>= 'A' and <= 'F') or (>= 'a' and <= 'f');
|
||||
|
||||
public static int AsHex(char c)
|
||||
{
|
||||
if (c <= '9')
|
||||
return c - '0';
|
||||
|
||||
if (c <= 'F')
|
||||
return c - 'A' + 10;
|
||||
|
||||
return c - 'a' + 10;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user