Created
March 8, 2019 16:12
-
-
Save gcapnias/945d69a99267ee94d9d629e40e9e1c77 to your computer and use it in GitHub Desktop.
Creates a URL And SEO friendly slug with Greek language support
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /// <summary> | |
| /// Creates a URL And SEO friendly slug | |
| /// </summary> | |
| /// <param name="normalText">Text to slugify</param> | |
| /// <param name="maxLength">Max length of slug</param> | |
| /// <returns>URL and SEO friendly string</returns> | |
| /// <remarks>Inspired from: https://www.johanbostrom.se/blog/how-to-create-a-url-and-seo-friendly-string-in-csharp-text-to-slug-generator </remarks> | |
| public static string UrlFriendly(this string normalText, int maxLength = 0) | |
| { | |
| // Return empty value if text is null | |
| if (string.IsNullOrEmpty(normalText)) | |
| { | |
| return string.Empty; | |
| } | |
| string normalizedString = normalText.ToLowerInvariant().Normalize(NormalizationForm.FormD); | |
| string[] findings = { "αυ", "γγ", "γκ", "γξ", "γχ", "ευ", "ηυ", "μπ", "ντ", "ου", "ού", "υι" }; | |
| string[] replacements = { "au", "ng", "nk", "nx", "nch", "eu", "eu", "b", "d", "ou", "ou", "yi" }; | |
| for (int i = 0; i < findings.Length; i++) | |
| { | |
| string searchToken = findings[i]; | |
| string[] tokens = normalizedString.Split(new string[] { searchToken }, StringSplitOptions.None); | |
| if (tokens.Length > 1) | |
| { | |
| string replaceToken = replacements[i]; | |
| normalizedString = string.Join(replaceToken, tokens); | |
| } | |
| } | |
| var stringBuilder = new StringBuilder(); | |
| var stringLength = normalizedString.Length; | |
| var prevdash = false; | |
| var trueLength = 0; | |
| char c; | |
| for (int i = 0; i < stringLength; i++) | |
| { | |
| c = normalizedString[i]; | |
| switch (CharUnicodeInfo.GetUnicodeCategory(c)) | |
| { | |
| // Check if the character is a letter or a digit if the character is a | |
| // international character remap it to an ascii valid character | |
| case UnicodeCategory.LowercaseLetter: | |
| case UnicodeCategory.UppercaseLetter: | |
| case UnicodeCategory.DecimalDigitNumber: | |
| if (c < 128) | |
| { | |
| stringBuilder.Append(c); | |
| } | |
| else | |
| { | |
| stringBuilder.Append(c.RemapInternationalCharToAscii()); | |
| } | |
| prevdash = false; | |
| trueLength = stringBuilder.Length; | |
| break; | |
| // Check if the character is to be replaced by a hyphen but only if the last character wasn't | |
| case UnicodeCategory.SpaceSeparator: | |
| case UnicodeCategory.ConnectorPunctuation: | |
| case UnicodeCategory.DashPunctuation: | |
| case UnicodeCategory.OtherPunctuation: | |
| case UnicodeCategory.MathSymbol: | |
| if (!prevdash) | |
| { | |
| stringBuilder.Append('-'); | |
| prevdash = true; | |
| trueLength = stringBuilder.Length; | |
| } | |
| break; | |
| } | |
| // If we are at max length, stop parsing | |
| if (maxLength > 0 && trueLength >= maxLength) | |
| { | |
| break; | |
| } | |
| } | |
| // Trim excess hyphens | |
| var result = stringBuilder.ToString().Trim('-'); | |
| // Remove any excess character to meet maxlength criteria | |
| return maxLength <= 0 || result.Length <= maxLength ? result : result.Substring(0, maxLength); | |
| } | |
| /// <summary> | |
| /// Remaps international characters to ascii compatible ones | |
| /// based of: https://meta.stackexchange.com/questions/7435/non-us-ascii-characters-dropped-from-full-profile-url/7696#7696 | |
| /// </summary> | |
| /// <param name="c">Charcter to remap</param> | |
| /// <returns>Remapped character</returns> | |
| public static string RemapInternationalCharToAscii(this char c) | |
| { | |
| string lowerText = c.ToString().ToLowerInvariant(); | |
| if ("αά".Contains(lowerText)) | |
| { | |
| return "a"; | |
| } | |
| else if (c == 'β') | |
| { | |
| return "b"; | |
| } | |
| else if (c == 'γ') | |
| { | |
| return "g"; | |
| } | |
| else if (c == 'δ') | |
| { | |
| return "d"; | |
| } | |
| else if ("εέ".Contains(lowerText)) | |
| { | |
| return "e"; | |
| } | |
| else if (c == 'ζ') | |
| { | |
| return "z"; | |
| } | |
| else if ("ηή".Contains(lowerText)) | |
| { | |
| return "e"; | |
| } | |
| else if (c == 'θ') | |
| { | |
| return "th"; | |
| } | |
| else if ("ιίΐ".Contains(lowerText)) | |
| { | |
| return "i"; | |
| } | |
| else if (c == 'κ') | |
| { | |
| return "k"; | |
| } | |
| else if (c == 'λ') | |
| { | |
| return "l"; | |
| } | |
| else if (c == 'μ') | |
| { | |
| return "m"; | |
| } | |
| else if (c == 'ν') | |
| { | |
| return "n"; | |
| } | |
| else if (c == 'ξ') | |
| { | |
| return "x"; | |
| } | |
| else if ("οό".Contains(lowerText)) | |
| { | |
| return "o"; | |
| } | |
| else if (c == 'π') | |
| { | |
| return "p"; | |
| } | |
| else if (c == 'ρ') | |
| { | |
| return "r"; | |
| } | |
| else if ("σς".Contains(lowerText)) | |
| { | |
| return "s"; | |
| } | |
| else if (c == 'τ') | |
| { | |
| return "t"; | |
| } | |
| else if ("υύΰ".Contains(lowerText)) | |
| { | |
| return "y"; | |
| } | |
| else if (c == 'φ') | |
| { | |
| return "ph"; | |
| } | |
| else if (c == 'χ') | |
| { | |
| return "ch"; | |
| } | |
| else if (c == 'ψ') | |
| { | |
| return "ps"; | |
| } | |
| else if ("ωώ".Contains(lowerText)) | |
| { | |
| return "o"; | |
| } | |
| else | |
| { | |
| return string.Empty; | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment