using System.Text; namespace IOL.Helpers; public static class Slug { public static string Generate(bool toLower, params string[] values) { return Create(string.Join("-", values), toLower); } /// /// Creates a slug. /// References: /// http://www.unicode.org/reports/tr15/tr15-34.html /// https://meta.stackexchange.com/questions/7435/non-us-ascii-characters-dropped-from-full-profile-url/7696#7696 /// https://stackoverflow.com/questions/25259/how-do-you-include-a-webpage-title-as-part-of-a-webpage-url/25486#25486 /// https://stackoverflow.com/questions/3769457/how-can-i-remove-accents-on-a-string /// /// /// /// Slugified string public static string Create(string value, bool toLower) { if (string.IsNullOrWhiteSpace(value)) return value; var normalised = value.Normalize(NormalizationForm.FormKD); const int MAXLEN = 80; var len = normalised.Length; var prevDash = false; var sb = new StringBuilder(len); for (var i = 0; i < len; i++) { var c = normalised[i]; switch (c) { case >= 'a' and <= 'z': case >= '0' and <= '9': { if (prevDash) { sb.Append('-'); prevDash = false; } sb.Append(c); break; } case >= 'A' and <= 'Z': { if (prevDash) { sb.Append('-'); prevDash = false; } // Tricky way to convert to lowercase if (toLower) sb.Append((char)(c | 32)); else sb.Append(c); break; } case ' ': case ',': case '.': case '/': case '\\': case '-': case '_': case '=': { if (!prevDash && sb.Length > 0) { prevDash = true; } break; } default: { var swap = ConvertEdgeCases(c, toLower); if (swap != null) { if (prevDash) { sb.Append('-'); prevDash = false; } sb.Append(swap); } break; } } if (sb.Length == MAXLEN) break; } return sb.ToString(); } private static string ConvertEdgeCases(char c, bool toLower) => c switch { 'ı' => "i", 'ł' => "l", 'Ł' => toLower ? "l" : "L", 'đ' => "d", 'ß' => "ss", 'ø' => "o", 'å' => "aa", 'æ' => "ae", 'Þ' => "th", _ => null }; }