Skip to content

Instantly share code, notes, and snippets.

@gcapnias
Created March 8, 2019 16:12
Show Gist options
  • Select an option

  • Save gcapnias/945d69a99267ee94d9d629e40e9e1c77 to your computer and use it in GitHub Desktop.

Select an option

Save gcapnias/945d69a99267ee94d9d629e40e9e1c77 to your computer and use it in GitHub Desktop.
Creates a URL And SEO friendly slug with Greek language support
/// <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