diff --git a/src/Slugify.Core/SlugHelper.cs b/src/Slugify.Core/SlugHelper.cs index 6a900c7..33accc2 100644 --- a/src/Slugify.Core/SlugHelper.cs +++ b/src/Slugify.Core/SlugHelper.cs @@ -46,72 +46,6 @@ public string GenerateSlug(string inputString) return inputString; } - public string GenerateSlug2(string inputString) - { - if (_config.TrimWhitespace) - { - inputString = inputString.Trim(); - } - - if (_config.ForceLowerCase) - { - inputString = inputString.ToLower(); - } - - inputString = CleanWhiteSpace(inputString, _config.CollapseWhiteSpace); - inputString = ApplyReplacements(inputString, _config.StringReplacements); - inputString = RemoveDiacritics(inputString); - inputString = DeleteCharacters(inputString, _config.DeniedCharactersRegex); - - if (_config.CollapseDashes) - { - inputString = Regex.Replace(inputString, "--+", "-"); - } - - return inputString; - - string CleanWhiteSpace(string str, bool collapse) - { - return Regex.Replace(str, collapse ? @"\s+" : @"\s", " "); - } - - string RemoveDiacritics(string str) - { - var stFormD = str.Normalize(NormalizationForm.FormD); - var sb = new StringBuilder(stFormD.Length); - - - for (var ich = 0; ich < stFormD.Length; ich++) - { - var uc = CharUnicodeInfo.GetUnicodeCategory(stFormD[ich]); - if (uc != UnicodeCategory.NonSpacingMark) - { - sb.Append(stFormD[ich]); - } - } - - return sb.ToString().Normalize(NormalizationForm.FormC); - } - - - string ApplyReplacements(string str, Dictionary replacements) - { - foreach (var replacement in replacements) - { - str = str.Replace(replacement.Key, replacement.Value); - } - - return str; - } - - string DeleteCharacters(string str, string regex) - { - return Regex.Replace(str, regex, ""); - } - - } - - protected string CleanWhiteSpace(string str, bool collapse) { return Regex.Replace(str, collapse ? @"\s+" : @"\s", " "); diff --git a/src/Slugify.Core/SlugHelperImproved.cs b/src/Slugify.Core/SlugHelperImproved.cs new file mode 100644 index 0000000..5960694 --- /dev/null +++ b/src/Slugify.Core/SlugHelperImproved.cs @@ -0,0 +1,100 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Text; +using System.Text.RegularExpressions; +using System.Xml; + +namespace Slugify +{ + public class SlugHelperImproved : ISlugHelper + { + protected SlugHelper.Config _config { get; set; } + + private readonly Regex _deniedCharactersRegex; + private readonly Regex _cleanWhiteSpaceRegex; + private readonly Regex _collapseDashesRegex; + + public SlugHelperImproved() : this(new SlugHelper.Config()) { } + + public SlugHelperImproved(SlugHelper.Config config) + { + _config = config ?? throw new ArgumentNullException(nameof(config), "can't be null use default config or empty constructor."); + + _deniedCharactersRegex = new Regex(_config.DeniedCharactersRegex, RegexOptions.Compiled); + _cleanWhiteSpaceRegex = new Regex(_config.CollapseWhiteSpace ? @"\s+" : @"\s", RegexOptions.Compiled); + _collapseDashesRegex = new Regex("--+", RegexOptions.Compiled); + } + + /// + /// Implements + /// + public string GenerateSlug(string inputString) + { + if (_config.TrimWhitespace) + { + inputString = inputString.Trim(); + } + + if (_config.ForceLowerCase) + { + inputString = inputString.ToLower(); + } + + inputString = CleanWhiteSpace(inputString); + inputString = ApplyReplacements(inputString); + inputString = RemoveDiacritics(inputString); + inputString = DeleteCharacters(inputString); + + if (_config.CollapseDashes) + { + inputString = _collapseDashesRegex.Replace(inputString, "-"); + } + + return inputString; + } + + + protected string CleanWhiteSpace(string str) + { + return _cleanWhiteSpaceRegex.Replace(str, " "); + } + + // Thanks http://stackoverflow.com/a/249126! + protected string RemoveDiacritics(string str) + { + var stFormD = str.Normalize(NormalizationForm.FormD); + + //perf: initialise this with the length of the chars + var sb = new StringBuilder(stFormD.Length); + + for (var ich = 0; ich < stFormD.Length; ich++) + { + var uc = CharUnicodeInfo.GetUnicodeCategory(stFormD[ich]); + if (uc != UnicodeCategory.NonSpacingMark) + { + sb.Append(stFormD[ich]); + } + } + + return sb.ToString().Normalize(NormalizationForm.FormC); + } + + protected string ApplyReplacements(string str) + { + //perf: don't use string builder here, it's faster without + foreach (var replacement in _config.StringReplacements) + { + str = str.Replace(replacement.Key, replacement.Value); + } + + return str; + } + + protected string DeleteCharacters(string str) + { + return _deniedCharactersRegex.Replace(str, string.Empty); + } + } +} + diff --git a/src/Slugify.Core/Slugify.Core.csproj b/src/Slugify.Core/Slugify.Core.csproj index f83b66f..ef095dd 100644 --- a/src/Slugify.Core/Slugify.Core.csproj +++ b/src/Slugify.Core/Slugify.Core.csproj @@ -35,6 +35,7 @@ With default settings, you will get an hyphenized, lowercase, alphanumeric versi runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/tests/Slugify.Core.Benchmarks/BenchmarkDotNet.Artifacts/results/Slugify.Core.Benchmarks.SlugifyBenchmarks-report-github.md b/tests/Slugify.Core.Benchmarks/BenchmarkDotNet.Artifacts/results/Slugify.Core.Benchmarks.SlugifyBenchmarks-report-github.md index d325c40..8c58301 100644 --- a/tests/Slugify.Core.Benchmarks/BenchmarkDotNet.Artifacts/results/Slugify.Core.Benchmarks.SlugifyBenchmarks-report-github.md +++ b/tests/Slugify.Core.Benchmarks/BenchmarkDotNet.Artifacts/results/Slugify.Core.Benchmarks.SlugifyBenchmarks-report-github.md @@ -8,10 +8,7 @@ Intel Core i9-9900K CPU 3.60GHz (Coffee Lake), 1 CPU, 16 logical and 8 physical ``` -| Method | N | word | Mean | Error | StdDev | Ratio | RatioSD | Gen 0 | Gen 1 | Gen 2 | Allocated | -|--------- |-- |--------------------- |-----------:|---------:|---------:|------:|--------:|-------:|------:|------:|----------:| -| **Baseline** | **1** | **Hello** | **660.0 ns** | **2.01 ns** | **1.78 ns** | **1.00** | **0.00** | **0.0734** | **-** | **-** | **616 B** | -| Improved | 1 | Hello | 643.8 ns | 12.74 ns | 11.92 ns | 0.98 | 0.02 | 0.0553 | - | - | 464 B | -| | | | | | | | | | | | | -| **Baseline** | **1** | **lorem(...)oot!! [40]** | **4,174.1 ns** | **11.46 ns** | **10.72 ns** | **1.00** | **0.00** | **0.4501** | **-** | **-** | **3824 B** | -| Improved | 1 | lorem(...)oot!! [40] | 3,924.9 ns | 7.03 ns | 5.87 ns | 0.94 | 0.00 | 0.3967 | - | - | 3360 B | +| Method | Mean | Error | StdDev | Ratio | Gen 0 | Gen 1 | Gen 2 | Allocated | +|--------- |---------:|---------:|---------:|------:|----------:|------:|------:|----------:| +| Baseline | 42.32 ms | 0.045 ms | 0.040 ms | 1.00 | 3750.0000 | - | - | 30.57 MB | +| Improved | 26.14 ms | 0.323 ms | 0.287 ms | 0.62 | 2562.5000 | - | - | 20.6 MB | diff --git a/tests/Slugify.Core.Benchmarks/BenchmarkDotNet.Artifacts/results/Slugify.Core.Benchmarks.SlugifyBenchmarks-report.csv b/tests/Slugify.Core.Benchmarks/BenchmarkDotNet.Artifacts/results/Slugify.Core.Benchmarks.SlugifyBenchmarks-report.csv index 7e5a40e..0ad5aaf 100644 --- a/tests/Slugify.Core.Benchmarks/BenchmarkDotNet.Artifacts/results/Slugify.Core.Benchmarks.SlugifyBenchmarks-report.csv +++ b/tests/Slugify.Core.Benchmarks/BenchmarkDotNet.Artifacts/results/Slugify.Core.Benchmarks.SlugifyBenchmarks-report.csv @@ -1,5 +1,3 @@ -Method,Job,AnalyzeLaunchVariance,EvaluateOverhead,MaxAbsoluteError,MaxRelativeError,MinInvokeCount,MinIterationTime,OutlierMode,Affinity,EnvironmentVariables,Jit,Platform,PowerPlanMode,Runtime,AllowVeryLargeObjects,Concurrent,CpuGroups,Force,HeapAffinitizeMask,HeapCount,NoAffinitize,RetainVm,Server,Arguments,BuildConfiguration,Clock,EngineFactory,NuGetReferences,Toolchain,IsMutator,InvocationCount,IterationCount,IterationTime,LaunchCount,MaxIterationCount,MaxWarmupIterationCount,MinIterationCount,MinWarmupIterationCount,RunStrategy,UnrollFactor,WarmupCount,N,word,Mean,Error,StdDev,Ratio,RatioSD,Gen 0,Gen 1,Gen 2,Allocated -Baseline,DefaultJob,False,Default,Default,Default,Default,Default,Default,1111111111111111,Empty,RyuJit,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET Core 3.1,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,1,Default,Default,Default,Default,Default,Default,Default,Default,16,Default,1,Hello,660.0 ns,2.01 ns,1.78 ns,1.00,0.00,0.0734,0.0000,0.0000,616 B -Improved,DefaultJob,False,Default,Default,Default,Default,Default,Default,1111111111111111,Empty,RyuJit,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET Core 3.1,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,1,Default,Default,Default,Default,Default,Default,Default,Default,16,Default,1,Hello,643.8 ns,12.74 ns,11.92 ns,0.98,0.02,0.0553,0.0000,0.0000,464 B -Baseline,DefaultJob,False,Default,Default,Default,Default,Default,Default,1111111111111111,Empty,RyuJit,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET Core 3.1,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,1,Default,Default,Default,Default,Default,Default,Default,Default,16,Default,1,lorem(...)oot!! [40],"4,174.1 ns",11.46 ns,10.72 ns,1.00,0.00,0.4501,0.0000,0.0000,3824 B -Improved,DefaultJob,False,Default,Default,Default,Default,Default,Default,1111111111111111,Empty,RyuJit,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET Core 3.1,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,1,Default,Default,Default,Default,Default,Default,Default,Default,16,Default,1,lorem(...)oot!! [40],"3,924.9 ns",7.03 ns,5.87 ns,0.94,0.00,0.3967,0.0000,0.0000,3360 B +Method,Job,AnalyzeLaunchVariance,EvaluateOverhead,MaxAbsoluteError,MaxRelativeError,MinInvokeCount,MinIterationTime,OutlierMode,Affinity,EnvironmentVariables,Jit,Platform,PowerPlanMode,Runtime,AllowVeryLargeObjects,Concurrent,CpuGroups,Force,HeapAffinitizeMask,HeapCount,NoAffinitize,RetainVm,Server,Arguments,BuildConfiguration,Clock,EngineFactory,NuGetReferences,Toolchain,IsMutator,InvocationCount,IterationCount,IterationTime,LaunchCount,MaxIterationCount,MaxWarmupIterationCount,MinIterationCount,MinWarmupIterationCount,RunStrategy,UnrollFactor,WarmupCount,Mean,Error,StdDev,Ratio,Gen 0,Gen 1,Gen 2,Allocated +Baseline,DefaultJob,False,Default,Default,Default,Default,Default,Default,1111111111111111,Empty,RyuJit,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET Core 3.1,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,1,Default,Default,Default,Default,Default,Default,Default,Default,16,Default,42.32 ms,0.045 ms,0.040 ms,1.00,3750.0000,0.0000,0.0000,30.57 MB +Improved,DefaultJob,False,Default,Default,Default,Default,Default,Default,1111111111111111,Empty,RyuJit,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET Core 3.1,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,1,Default,Default,Default,Default,Default,Default,Default,Default,16,Default,26.14 ms,0.323 ms,0.287 ms,0.62,2562.5000,0.0000,0.0000,20.6 MB diff --git a/tests/Slugify.Core.Benchmarks/BenchmarkDotNet.Artifacts/results/Slugify.Core.Benchmarks.SlugifyBenchmarks-report.html b/tests/Slugify.Core.Benchmarks/BenchmarkDotNet.Artifacts/results/Slugify.Core.Benchmarks.SlugifyBenchmarks-report.html index 8a6fede..21b55c3 100644 --- a/tests/Slugify.Core.Benchmarks/BenchmarkDotNet.Artifacts/results/Slugify.Core.Benchmarks.SlugifyBenchmarks-report.html +++ b/tests/Slugify.Core.Benchmarks/BenchmarkDotNet.Artifacts/results/Slugify.Core.Benchmarks.SlugifyBenchmarks-report.html @@ -2,7 +2,7 @@ -Slugify.Core.Benchmarks.SlugifyBenchmarks-20200430-160656 +Slugify.Core.Benchmarks.SlugifyBenchmarks-20200430-175237