From 9e0fbac6d3cb4e11efdb33c339ccf0adbca0bc6c Mon Sep 17 00:00:00 2001 From: ivarlovlie Date: Thu, 1 Apr 2021 22:36:59 +0200 Subject: Initial commit --- src/IOL.Helpers/SlugGenerator.cs | 108 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 src/IOL.Helpers/SlugGenerator.cs (limited to 'src/IOL.Helpers/SlugGenerator.cs') diff --git a/src/IOL.Helpers/SlugGenerator.cs b/src/IOL.Helpers/SlugGenerator.cs new file mode 100644 index 0000000..3f53dd6 --- /dev/null +++ b/src/IOL.Helpers/SlugGenerator.cs @@ -0,0 +1,108 @@ +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 + }; + } +} \ No newline at end of file -- cgit v1.3