Headless CMS and Content Managment Hub
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

439 lines
12 KiB

// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschränkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
namespace Squidex.Infrastructure
{
public static class StringExtensions
{
private static readonly Regex SlugRegex = new Regex("^[a-z0-9]+(\\-[a-z0-9]+)*$", RegexOptions.Compiled);
private static readonly Regex PropertyNameRegex = new Regex("^[a-zA-Z0-9]+(\\-[a-zA-Z0-9]+)*$", RegexOptions.Compiled);
private static readonly Dictionary<char, string> LowerCaseDiacritics;
private static readonly Dictionary<char, string> Diacritics = new Dictionary<char, string>
{
['À'] = "A",
['à'] = "a",
['Ā'] = "A",
['Ġ'] = "G",
['ŀ'] = "l",
['Š'] = "S",
['Ǡ'] = "A",
['Ȁ'] = "A",
['Á'] = "A",
['á'] = "a",
['ā'] = "a",
['ġ'] = "g",
['Ł'] = "L",
['š'] = "s",
['ǡ'] = "a",
['ȁ'] = "a",
['Â'] = "A",
['â'] = "a",
['Ă'] = "A",
['Ģ'] = "G",
['ł'] = "l",
['Ţ'] = "T",
['Ǣ'] = "Ae",
['Ȃ'] = "A",
['Ã'] = "A",
['ã'] = "a",
['ă'] = "a",
['ģ'] = "g",
['Ń'] = "N",
['ţ'] = "t",
['ǣ'] = "ae",
['ȃ'] = "a",
['Ä'] = "Ae",
['ä'] = "ae",
['Ą'] = "A",
['Ĥ'] = "H",
['ń'] = "n",
['Ť'] = "T",
['DŽ'] = "DZ",
['Ǥ'] = "G",
['Ȅ'] = "E",
['Å'] = "A",
['å'] = "a",
['ą'] = "a",
['ĥ'] = "h",
['Ņ'] = "N",
['ť'] = "t",
['Dž'] = "Dz",
['ǥ'] = "g",
['ȅ'] = "e",
['Æ'] = "AE",
['æ'] = "ae",
['Ć'] = "C",
['Ħ'] = "H",
['ņ'] = "n",
['Ŧ'] = "T",
['dž'] = "dz",
['Ǧ'] = "G",
['Ȇ'] = "E",
['Ç'] = "C",
['ç'] = "c",
['ć'] = "c",
['ħ'] = "h",
['Ň'] = "N",
['ŧ'] = "t",
['LJ'] = "W",
['ǧ'] = "g",
['ȇ'] = "e",
['È'] = "E",
['è'] = "E",
['Ĉ'] = "C",
['Ĩ'] = "I",
['ň'] = "n",
['Ũ'] = "U",
['Lj'] = "Lj",
['Ǩ'] = "K",
['Ȉ'] = "I",
['É'] = "E",
['é'] = "e",
['ĉ'] = "c",
['ĩ'] = "i",
['ʼn'] = "n",
['ũ'] = "u",
['lj'] = "lj",
['ǩ'] = "k",
['ȉ'] = "i",
['Ê'] = "E",
['ê'] = "e",
['Ċ'] = "C",
['Ī'] = "I",
['Ŋ'] = "n",
['Ū'] = "U",
['NJ'] = "NJ",
['Ǫ'] = "O",
['Ȋ'] = "I",
['Ë'] = "E",
['ë'] = "e",
['ċ'] = "c",
['ī'] = "i",
['ŋ'] = "n",
['ū'] = "u",
['Nj'] = "Nj",
['ǫ'] = "o",
['ȋ'] = "i",
['Ì'] = "I",
['ì'] = "i",
['Č'] = "C",
['Ĭ'] = "I",
['Ō'] = "O",
['Ŭ'] = "U",
['nj'] = "nj",
['Ǭ'] = "O",
['Ȍ'] = "O",
['Í'] = "I",
['í'] = "i",
['č'] = "c",
['ĭ'] = "i",
['ō'] = "o",
['ŭ'] = "u",
['Ǎ'] = "A",
['ǭ'] = "o",
['ȍ'] = "o",
['Î'] = "I",
['î'] = "i",
['Ď'] = "D",
['Į'] = "I",
['Ŏ'] = "O",
['Ů'] = "U",
['ǎ'] = "a",
['Ǯ'] = "z",
['Ȏ'] = "O",
['Ï'] = "I",
['ï'] = "i",
['ď'] = "d",
['į'] = "i",
['ŏ'] = "o",
['ů'] = "u",
['Ǐ'] = "I",
['ǯ'] = "z",
['ȏ'] = "o",
['Ð'] = "D",
['ð'] = "d",
['Đ'] = "D",
['İ'] = "I",
['Ő'] = "O",
['Ű'] = "U",
['ǐ'] = "i",
['ǰ'] = "j",
['Ȑ'] = "R",
['Ñ'] = "N",
['ñ'] = "n",
['đ'] = "d",
['ı'] = "i",
['ő'] = "o",
['ű'] = "u",
['Ǒ'] = "O",
['DZ'] = "DZ",
['ȑ'] = "r",
['Ò'] = "O",
['ò'] = "o",
['Ē'] = "E",
['IJ'] = "LJ",
['Œ'] = "OE",
['Ų'] = "U",
['ǒ'] = "o",
['Dz'] = "Dz",
['Ȓ'] = "R",
['Ó'] = "O",
['ó'] = "o",
['ē'] = "e",
['ij'] = "ij",
['œ'] = "oe",
['ų'] = "u",
['Ǔ'] = "U",
['dz'] = "dz",
['ȓ'] = "r",
['Ô'] = "O",
['ô'] = "o",
['Ĕ'] = "E",
['Ĵ'] = "J",
['Ŕ'] = "R",
['Ŵ'] = "W",
['ǔ'] = "u",
['Ǵ'] = "G",
['Ȕ'] = "U",
['Õ'] = "O",
['õ'] = "o",
['ĕ'] = "e",
['ĵ'] = "j",
['ŕ'] = "r",
['ŵ'] = "w",
['Ǖ'] = "U",
['ǵ'] = "g",
['ȕ'] = "u",
['Ö'] = "Oe",
['ö'] = "oe",
['Ė'] = "E",
['Ķ'] = "K",
['Ŗ'] = "R",
['Ŷ'] = "Y",
['ǖ'] = "u",
['Ƕ'] = "Hj",
['Ȗ'] = "U",
['ė'] = "e",
['ķ'] = "k",
['ŗ'] = "r",
['ŷ'] = "y",
['Ǘ'] = "U",
['ȗ'] = "u",
['Ø'] = "O",
['ø'] = "o",
['Ę'] = "E",
['ĸ'] = "k",
['Ř'] = "R",
['Ÿ'] = "Y",
['ǘ'] = "u",
['Ǹ'] = "N",
['Ș'] = "S",
['Ù'] = "U",
['ù'] = "u",
['ę'] = "e",
['Ĺ'] = "L",
['ř'] = "r",
['Ź'] = "Z",
['Ǚ'] = "U",
['ǹ'] = "n",
['ș'] = "s",
['Ú'] = "U",
['ú'] = "u",
['Ě'] = "E",
['ĺ'] = "l",
['Ś'] = "S",
['ź'] = "z",
['ǚ'] = "u",
['Ǻ'] = "A",
['Ț'] = "T",
['Û'] = "U",
['û'] = "u",
['ě'] = "e",
['Ļ'] = "L",
['ś'] = "s",
['Ż'] = "Z",
['Ǜ'] = "U",
['ǻ'] = "a",
['ț'] = "t",
['Ü'] = "Ue",
['ü'] = "ue",
['Ĝ'] = "G",
['ļ'] = "l",
['Ŝ'] = "S",
['ż'] = "z",
['ǜ'] = "u",
['Ǽ'] = "AE",
['Ȝ'] = "z",
['Ý'] = "Y",
['ý'] = "y",
['ĝ'] = "g",
['Ľ'] = "L",
['ŝ'] = "s",
['Ž'] = "Z",
['ǝ'] = "e",
['ǽ'] = "ae",
['ȝ'] = "z",
['Þ'] = "p",
['þ'] = "p",
['Ğ'] = "G",
['ľ'] = "L",
['Ş'] = "S",
['ž'] = "z",
['Ǟ'] = "A",
['Ǿ'] = "O",
['Ȟ'] = "H",
['ß'] = "ss",
['ÿ'] = "y",
['ğ'] = "g",
['Ŀ'] = "L",
['ş'] = "s",
['ſ'] = "l",
['ǟ'] = "a",
['ǿ'] = "o",
['ȟ'] = "h"
};
static StringExtensions()
{
LowerCaseDiacritics = Diacritics.ToDictionary(x => x.Key, x => x.Value.ToLowerInvariant());
}
public static bool IsSlug(this string value)
{
return value != null && SlugRegex.IsMatch(value);
}
public static bool IsPropertyName(this string value)
{
return value != null && PropertyNameRegex.IsMatch(value);
}
public static string WithFallback(this string value, string fallback)
{
return !string.IsNullOrWhiteSpace(value) ? value.Trim() : fallback;
}
public static string ToPascalCase(this string value)
{
var sb = new StringBuilder();
foreach (var part in value.Split(new[] { '-', '_', ' ' }, StringSplitOptions.RemoveEmptyEntries))
{
if (part.Length < 2)
{
sb.Append(part.ToUpper());
}
else
{
sb.Append(char.ToUpper(part[0]));
sb.Append(part.Substring(1));
}
}
return sb.ToString();
}
public static string ToKebabCase(this string value)
{
var sb = new StringBuilder();
foreach (var part in value.Split(new[] { '-', '_', ' ' }, StringSplitOptions.RemoveEmptyEntries))
{
if (sb.Length > 0)
{
sb.Append("-");
}
sb.Append(part.ToLower());
}
return sb.ToString();
}
public static string ToCamelCase(this string value)
{
value = value.ToPascalCase();
if (value.Length < 2)
{
return value.ToLower();
}
else
{
return char.ToLower(value[0]) + value.Substring(1);
}
}
public static string Slugify(this string value, ISet<char> preserveHash = null, bool singleCharDiactric = false, char separator = '-')
{
var result = new StringBuilder(value.Length);
var lastChar = (char)0;
for (var i = 0; i < value.Length; i++)
{
var character = value[i];
if (preserveHash?.Contains(character) == true)
{
result.Append(character);
}
else if (char.IsLetter(character) || char.IsNumber(character))
{
lastChar = character;
var lower = char.ToLowerInvariant(character);
if (LowerCaseDiacritics.TryGetValue(character, out var replacement))
{
if (singleCharDiactric)
{
result.Append(replacement[0]);
}
else
{
result.Append(replacement);
}
}
else
{
result.Append(lower);
}
}
else if ((i < value.Length - 1) && (i > 0 && lastChar != separator))
{
lastChar = separator;
result.Append(separator);
}
}
return result.ToString().Trim(separator);
}
public static string BuildFullUrl(this string baseUrl, string path, bool trailingSlash = false)
{
var url = $"{baseUrl.TrimEnd('/')}/{path.Trim('/')}";
if (trailingSlash &&
url.IndexOf("#", StringComparison.OrdinalIgnoreCase) < 0 &&
url.IndexOf("?", StringComparison.OrdinalIgnoreCase) < 0 &&
url.IndexOf(";", StringComparison.OrdinalIgnoreCase) < 0)
{
url = url + "/";
}
return url;
}
}
}