diff --git a/README.md b/README.md
index 11def20..b50fcd4 100644
--- a/README.md
+++ b/README.md
@@ -214,4 +214,37 @@ Specifying the `DeniedCharactersRegex` option will disable the character removal
This will limit the length of the generated slug to be a maximum of the number of chars given by the parameter. If the truncation happens in a way that a trailing `-` is left, it will be removed.
-- Default value: `null`
\ No newline at end of file
+- Default value: `null`
+
+### `TrimChars`, `TrimEndChars`, `TrimStartChars`
+
+Trim options to remove characters from the input before replacements and character filtering. This is useful to prevent generated slug to start/end with certain characters like dot.
+
+- Options
+ - `TrimChars` — characters to trim from both ends (behaves like `string.Trim(char[])`).
+ - `TrimEndChars` — characters to trim from the end (behaves like `string.TrimEnd(char[])`).
+ - `TrimStartChars` — characters to trim from the start (behaves like `string.TrimStart(char[])`).
+
+- Default value: all three are empty arrays (no extra trimming).
+
+- Example:
+
+```csharp
+var helper = new SlugHelper(new SlugHelperConfiguration
+{
+ TrimChars = ['.']
+});
+Console.WriteLine(helper.GenerateSlug(".hello world.")); // "hello-world"
+
+helper = new SlugHelper(new SlugHelperConfiguration
+{
+ TrimEndChars = ['.']
+});
+Console.WriteLine(helper.GenerateSlug(".hello world.")); // ".hello-world"
+
+helper = new SlugHelper(new SlugHelperConfiguration
+{
+ TrimStartChars = ['.']
+});
+Console.WriteLine(helper.GenerateSlug(".hello world.")); // "hello-world."
+```
diff --git a/src/Slugify.Core/SlugHelper.cs b/src/Slugify.Core/SlugHelper.cs
index 136090a..e64cb6c 100644
--- a/src/Slugify.Core/SlugHelper.cs
+++ b/src/Slugify.Core/SlugHelper.cs
@@ -38,6 +38,9 @@ public virtual string GenerateSlug(string inputString)
normalizedInput = normalizedInput.Normalize(NormalizationForm.FormD);
normalizedInput = Config.TrimWhitespace ? normalizedInput.Trim() : normalizedInput;
normalizedInput = Config.ForceLowerCase ? normalizedInput.ToLowerInvariant() : normalizedInput;
+ normalizedInput = Config.TrimChars.Length != 0 ? normalizedInput.Trim(Config.TrimChars) : normalizedInput;
+ normalizedInput = Config.TrimEndChars.Length != 0 ? normalizedInput.TrimEnd(Config.TrimEndChars) : normalizedInput;
+ normalizedInput = Config.TrimStartChars.Length != 0 ? normalizedInput.TrimStart(Config.TrimStartChars) : normalizedInput;
var sb = new StringBuilder(normalizedInput);
diff --git a/src/Slugify.Core/SlugHelperConfiguration.cs b/src/Slugify.Core/SlugHelperConfiguration.cs
index 3874aef..ebde1c0 100644
--- a/src/Slugify.Core/SlugHelperConfiguration.cs
+++ b/src/Slugify.Core/SlugHelperConfiguration.cs
@@ -61,6 +61,21 @@ public class SlugHelperConfiguration
///
public bool TrimWhitespace { get; set; } = true;
+ ///
+ /// List of characters to be trimmed (removed from both ends) from generated slug
+ ///
+ public char[] TrimChars { get; set; } = [];
+
+ ///
+ /// List of characters to be trimmed from end of the generated slug
+ ///
+ public char[] TrimEndChars { get; set; } = [];
+
+ ///
+ /// List of characters to be trimmed from start of the generated slug
+ ///
+ public char[] TrimStartChars { get; set; } = [];
+
///
/// Represents the maximum length of the slug. If the slug is longer than this value, it will be truncated.
///
diff --git a/tests/Slugify.Core.Tests/SlugHelperTests.cs b/tests/Slugify.Core.Tests/SlugHelperTests.cs
index e711ca9..3c1a5c7 100644
--- a/tests/Slugify.Core.Tests/SlugHelperTests.cs
+++ b/tests/Slugify.Core.Tests/SlugHelperTests.cs
@@ -512,6 +512,51 @@ public void TestNoTrimmingWithLeadingAndTrailingSpaces(ISlugHelper helper)
Assert.Equal(expected, helper.GenerateSlug(original));
}
+ [Theory]
+ [MemberData(nameof(GenerateStandardSluggers))]
+ public void TestTrimmingEndChars(ISlugHelper helper)
+ {
+ const string original = "hello._world._";
+ const string expected = "hello._world";
+
+ helper.Config = new SlugHelperConfiguration
+ {
+ TrimEndChars = [ '.', '_' ],
+ };
+
+ Assert.Equal(expected, helper.GenerateSlug(original));
+ }
+
+ [Theory]
+ [MemberData(nameof(GenerateStandardSluggers))]
+ public void TestTrimmingStartChars(ISlugHelper helper)
+ {
+ const string original = "._hello._world";
+ const string expected = "hello._world";
+
+ helper.Config = new SlugHelperConfiguration
+ {
+ TrimStartChars = [ '.', '_' ],
+ };
+
+ Assert.Equal(expected, helper.GenerateSlug(original));
+ }
+
+ [Theory]
+ [MemberData(nameof(GenerateStandardSluggers))]
+ public void TestTrimmingChars(ISlugHelper helper)
+ {
+ const string original = "._hello._world._";
+ const string expected = "hello._world";
+
+ helper.Config = new SlugHelperConfiguration
+ {
+ TrimChars = [ '.', '_' ],
+ };
+
+ Assert.Equal(expected, helper.GenerateSlug(original));
+ }
+
[Theory]
[MemberData(nameof(GenerateStandardSluggers))]
public void TestReplacementWithEmptyStringThenCollapsing(ISlugHelper helper)