using System.Globalization; using System.Text; namespace StellaOps.Canonicalization.Culture; /// /// Ensures all string operations use invariant culture. /// public static class InvariantCulture { public static IDisposable Scope() { var original = CultureInfo.CurrentCulture; var originalUi = CultureInfo.CurrentUICulture; CultureInfo.CurrentCulture = CultureInfo.InvariantCulture; CultureInfo.CurrentUICulture = CultureInfo.InvariantCulture; return new CultureScope(original, originalUi); } public static int Compare(string? a, string? b) => string.Compare(a, b, StringComparison.Ordinal); public static string FormatDecimal(decimal value) => value.ToString("G", CultureInfo.InvariantCulture); public static decimal ParseDecimal(string value) => decimal.Parse(value, CultureInfo.InvariantCulture); private sealed class CultureScope : IDisposable { private readonly CultureInfo _original; private readonly CultureInfo _originalUi; public CultureScope(CultureInfo original, CultureInfo originalUi) { _original = original; _originalUi = originalUi; } public void Dispose() { CultureInfo.CurrentCulture = _original; CultureInfo.CurrentUICulture = _originalUi; } } } /// /// UTF-8 encoding utilities. /// public static class Utf8Encoding { public static string Normalize(string input) => Normalize(input, NormalizationForm.FormC); public static string Normalize(string input, NormalizationForm form) => input.Normalize(form); public static byte[] GetBytes(string input) => Encoding.UTF8.GetBytes(Normalize(input)); public static byte[] GetBytes(string input, NormalizationForm form) => Encoding.UTF8.GetBytes(Normalize(input, form)); }