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; CultureInfo.CurrentCulture = CultureInfo.InvariantCulture; CultureInfo.CurrentUICulture = CultureInfo.InvariantCulture; return new CultureScope(original); } 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; public CultureScope(CultureInfo original) => _original = original; public void Dispose() { CultureInfo.CurrentCulture = _original; CultureInfo.CurrentUICulture = _original; } } } /// /// UTF-8 encoding utilities. /// public static class Utf8Encoding { public static string Normalize(string input) { return input.Normalize(NormalizationForm.FormC); } public static byte[] GetBytes(string input) => Encoding.UTF8.GetBytes(Normalize(input)); }