Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ Also Humanizer [symbols nuget package](http://www.symbolsource.org/Public/Metada
- [Number to ordinal words](#number-to-ordinal-words)
- [Roman numerals](#roman-numerals)
- [ByteSize](#bytesize)
- [Truncate](#truncate)
- [Mix this into your framework to simplify your life](#mix-this-into-your-framework-to-simplify-your-life)
- [How to contribute?](#how-to-contribute)
- [Contribution guideline](#contribution-guideline)
Expand Down Expand Up @@ -514,6 +515,34 @@ ByteSize.Parse("1.55 tB");
ByteSize.Parse("1.55 tb");
```

###<a id="truncate">Truncate</a>
You can truncate a `string` using the `Truncate` method:

```c#
"Long text to truncate".Truncate(10) => "Long text…"
```

By default the `'…'` character is used to truncate strings. The advantage of using the `'…'` character instead of `"..."` is that the former only takes a single character and thus allows more text to be shown before truncation. If you want, you can also provide your own truncation string:

```c#
"Long text to truncate".Truncate(10, "---") => "Long te---"
```

The default truncation strategy, `Truncator.FixedLength`, is to truncate the input string to a specific length, including the truncation string length. There are two more truncator strategies available: one for a fixed number of (alpha-numerical) characters and one for a fixed number of words. To use a specific truncator when truncating, the two `Truncate` methods shown in the previous examples both have an overload that allow you to specify the `ITruncator` instance to use for the truncation. Here are examples on how to use the three provided truncators:

```c#
"Long text to truncate".Truncate(10, Truncator.FixedLength) => "Long text…"
"Long text to truncate".Truncate(10, "---", Truncator.FixedLength) => "Long te---"

"Long text to truncate".Truncate(6, Truncator.FixedNumberOfCharacters) => "Long t…"
"Long text to truncate".Truncate(6, "---", Truncator.FixedNumberOfCharacters) => "Lon---"

"Long text to truncate".Truncate(2, Truncator.FixedNumberOfWords) => "Long text…"
"Long text to truncate".Truncate(2, "---", Truncator.FixedNumberOfWords) => "Long text---"
```

Note that you can also use create your own truncator by having a class implement the `ITruncator` interface.

###<a id="mix-this-into-your-framework-to-simplify-your-life">Mix this into your framework to simplify your life</a>
This is just a baseline and you can use this to simplify your day to day job. For example, in Asp.Net MVC we keep chucking `Display` attribute on ViewModel properties so `HtmlHelper` can generate correct labels for us; but, just like enums, in vast majority of cases we just need a space between the words in property name - so why not use `"string".Humanize` for that?!

Expand Down
2 changes: 2 additions & 0 deletions release_notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

[Commits](https://github.com/MehdiK/Humanizer/compare/v1.14.1...master)

- [#110](https://github.com/MehdiK/Humanizer/pull/110): Added `Truncate` feature

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should now point to #113. Sorry mate. My bad :)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey don't worry about this. I will fix it as part of release :)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool, thanks.


###v1.14.1 - 2014-03-26
- [#108](https://github.com/MehdiK/Humanizer/pull/108): Added support for custom description attributes
- [#106](https://github.com/MehdiK/Humanizer/pull/106):
Expand Down
1 change: 1 addition & 0 deletions src/Humanizer.Tests/Humanizer.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ApiApprover\PublicApiApprovalTest.cs" />
<Compile Include="ApiApprover\PublicApiGenerator.cs" />
<Compile Include="TruncatorTests.cs" />
</ItemGroup>
<ItemGroup>
<Compile Include="Localisation\DateHumanizeTests.fi-FI.cs" />
Expand Down
116 changes: 116 additions & 0 deletions src/Humanizer.Tests/TruncatorTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
using Xunit;
using Xunit.Extensions;

namespace Humanizer.Tests
{
public class TruncatorTests
{
[Theory]
[InlineData(null, 10, null)]
[InlineData("", 10, "")]
[InlineData("a", 1, "a")]
[InlineData("Text longer than truncate length", 10, "Text long�")]
[InlineData("Text with length equal to truncate length", 41, "Text with length equal to truncate length")]
[InlineData("Text smaller than truncate length", 34, "Text smaller than truncate length")]
public void Truncate(string input, int length, string expectedOutput)
{
Assert.Equal(expectedOutput, input.Truncate(length));
}

[Theory]
[InlineData(null, 10, null)]
[InlineData("", 10, "")]
[InlineData("a", 1, "a")]
[InlineData("Text longer than truncate length", 10, "Text long�")]
[InlineData("Text with length equal to truncate length", 41, "Text with length equal to truncate length")]
[InlineData("Text smaller than truncate length", 34, "Text smaller than truncate length")]
public void TruncateWithFixedLengthTruncator(string input, int length, string expectedOutput)
{
Assert.Equal(expectedOutput, input.Truncate(length, Truncator.FixedLength));
}

[Theory]
[InlineData(null, 10, null)]
[InlineData("", 10, "")]
[InlineData("a", 1, "a")]
[InlineData("Text with more characters than truncate length", 10, "Text with m�")]
[InlineData("Text with number of characters equal to truncate length", 47, "Text with number of characters equal to truncate length")]
[InlineData("Text with less characters than truncate length", 41, "Text with less characters than truncate length")]
public void TruncateWithFixedNumberOfCharactersTruncator(string input, int length, string expectedOutput)
{
Assert.Equal(expectedOutput, input.Truncate(length, Truncator.FixedNumberOfCharacters));
}

[Theory]
[InlineData(null, 10, null)]
[InlineData("", 10, "")]
[InlineData("a", 1, "a")]
[InlineData("Text with more words than truncate length", 4, "Text with more words�")]
[InlineData("Text with number of words equal to truncate length", 9, "Text with number of words equal to truncate length")]
[InlineData("Text with less words than truncate length", 8, "Text with less words than truncate length")]
[InlineData("Words are\nsplit\rby\twhitespace", 4, "Words are\nsplit\rby�")]
public void TruncateWithFixedNumberOfWordsTruncator(string input, int length, string expectedOutput)
{
Assert.Equal(expectedOutput, input.Truncate(length, Truncator.FixedNumberOfWords));
}

[Theory]
[InlineData(null, 10, "...", null)]
[InlineData("", 10, "...", "")]
[InlineData("a", 1, "...", "a")]
[InlineData("Text longer than truncate length", 10, "...", "Text lo...")]
[InlineData("Text with length equal to truncate length", 41, "...", "Text with length equal to truncate length")]
[InlineData("Text smaller than truncate length", 34, "...", "Text smaller than truncate length")]
[InlineData("Text with delimiter length greater than truncate length truncates to fixed length without truncation string", 2, "...", "Te")]
[InlineData("Null truncation string truncates to truncate length without truncation string", 4, null, "Null")]
public void TruncateWithTruncationString(string input, int length, string truncationString, string expectedOutput)
{
Assert.Equal(expectedOutput, input.Truncate(length, truncationString));
}

[Theory]
[InlineData(null, 10, "...", null)]
[InlineData("", 10, "...", "")]
[InlineData("a", 1, "...", "a")]
[InlineData("Text longer than truncate length", 10, "...", "Text lo...")]
[InlineData("Text with different truncation string", 10, "---", "Text wi---")]
[InlineData("Text with length equal to truncate length", 41, "...", "Text with length equal to truncate length")]
[InlineData("Text smaller than truncate length", 34, "...", "Text smaller than truncate length")]
[InlineData("Text with delimiter length greater than truncate length truncates to fixed length without truncation string", 2, "...", "Te")]
[InlineData("Null truncation string truncates to truncate length without truncation string", 4, null, "Null")]
public void TruncateWithTruncationStringAndFixedLengthTruncator(string input, int length, string truncationString, string expectedOutput)
{
Assert.Equal(expectedOutput, input.Truncate(length, truncationString, Truncator.FixedLength));
}

[Theory]
[InlineData(null, 10, "...", null)]
[InlineData("", 10, "...", "")]
[InlineData("a", 1, "...", "a")]
[InlineData("Text with more characters than truncate length", 10, "...", "Text wit...")]
[InlineData("Text with different truncation string", 10, "---", "Text wit---")]
[InlineData("Text with number of characters equal to truncate length", 47, "...", "Text with number of characters equal to truncate length")]
[InlineData("Text with less characters than truncate length", 41, "...", "Text with less characters than truncate length")]
[InlineData("Text with delimiter length greater than truncate length truncates to fixed length without truncation string", 2, "...", "Te")]
[InlineData("Null truncation string truncates to truncate length without truncation string", 4, null, "Null")]
public void TruncateWithTruncationStringAndFixedNumberOfCharactersTruncator(string input, int length, string truncationString, string expectedOutput)
{
Assert.Equal(expectedOutput, input.Truncate(length, truncationString, Truncator.FixedNumberOfCharacters));
}

[Theory]
[InlineData(null, 10, "...", null)]
[InlineData("", 10, "...", "")]
[InlineData("a", 1, "...", "a")]
[InlineData("Text with more words than truncate length", 4, "...", "Text with more words...")]
[InlineData("Text with different truncation string", 4, "---", "Text with different truncation---")]
[InlineData("Text with number of words equal to truncate length", 9, "...", "Text with number of words equal to truncate length")]
[InlineData("Text with less words than truncate length", 8, "...", "Text with less words than truncate length")]
[InlineData("Words are\nsplit\rby\twhitespace", 4, "...", "Words are\nsplit\rby...")]
[InlineData("Null truncation string truncates to truncate length without truncation string", 4, null, "Null truncation string truncates")]
public void TruncateWithTruncationStringAndFixedNumberOfWordsTruncator(string input, int length, string truncationString, string expectedOutput)
{
Assert.Equal(expectedOutput, input.Truncate(length, truncationString, Truncator.FixedNumberOfWords));
}
}
}
5 changes: 5 additions & 0 deletions src/Humanizer/Humanizer.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,11 @@
<Compile Include="Transformer\ToUpperCase.cs" />
<Compile Include="Transformer\ToLowerCase.cs" />
<Compile Include="Transformer\ToSentenceCase.cs" />
<Compile Include="Truncation\FixedLengthTruncator.cs" />
<Compile Include="Truncation\FixedNumberOfCharactersTruncator.cs" />
<Compile Include="Truncation\FixedNumberOfWordsTruncator.cs" />
<Compile Include="Truncation\ITruncator.cs" />
<Compile Include="Truncation\Truncator.cs" />
</ItemGroup>
<ItemGroup>
<None Include="FluentDate\In.SomeTimeFrom.tt">
Expand Down
1 change: 1 addition & 0 deletions src/Humanizer/Humanizer.csproj.DotSettings
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=FluentDate/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=Truncation/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=Resources/@EntryIndexedValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=Transformer/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
22 changes: 22 additions & 0 deletions src/Humanizer/Truncation/FixedLengthTruncator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
namespace Humanizer
{
/// <summary>
/// Truncate a string to a fixed length
/// </summary>
class FixedLengthTruncator : ITruncator
{
public string Truncate(string value, int length, string truncationString)
{
if (value == null)
return null;

if (value.Length == 0)
return value;

if (truncationString == null || truncationString.Length > length)
return value.Substring(0, length);

return value.Length > length ? value.Substring(0, length - truncationString.Length) + truncationString : value;
}
}
}
41 changes: 41 additions & 0 deletions src/Humanizer/Truncation/FixedNumberOfCharactersTruncator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using System;
using System.Linq;

namespace Humanizer
{
/// <summary>
/// Truncate a string to a fixed number of characters
/// </summary>
class FixedNumberOfCharactersTruncator : ITruncator
{
public string Truncate(string value, int length, string truncationString)
{
if (value == null)
return null;

if (value.Length == 0)
return value;

if (truncationString == null || truncationString.Length > length)
return value.Substring(0, length);

var alphaNumericalCharactersProcessed = 0;

var numberOfCharactersEqualToTruncateLength = value.ToCharArray().Count(Char.IsLetterOrDigit) == length;

for (var i = 0; i < value.Length - truncationString.Length; i++)
{
if (Char.IsLetterOrDigit(value[i]))
alphaNumericalCharactersProcessed++;

if (numberOfCharactersEqualToTruncateLength && alphaNumericalCharactersProcessed == length)
return value;

if (!numberOfCharactersEqualToTruncateLength && alphaNumericalCharactersProcessed + truncationString.Length == length)
return value.Substring(0, i + 1) + truncationString;
}

return value;
}
}
}
48 changes: 48 additions & 0 deletions src/Humanizer/Truncation/FixedNumberOfWordsTruncator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using System;
using System.Linq;

namespace Humanizer
{
/// <summary>
/// Truncate a string to a fixed number of words
/// </summary>
class FixedNumberOfWordsTruncator : ITruncator
{
public string Truncate(string value, int length, string truncationString)
{
if (value == null)
return null;

if (value.Length == 0)
return value;

var numberOfWordsProcessed = 0;
var numberOfWords = value.Split((char[])null, StringSplitOptions.RemoveEmptyEntries).Count();

if (numberOfWords <= length)
return value;

var lastCharactersWasWhiteSpace = true;

for (var i = 0; i < value.Length; i++)
{
if (Char.IsWhiteSpace(value[i]))
{
if (!lastCharactersWasWhiteSpace)
numberOfWordsProcessed++;

lastCharactersWasWhiteSpace = true;

if (numberOfWordsProcessed == length)
return value.Substring(0, i) + truncationString;
}
else
{
lastCharactersWasWhiteSpace = false;
}
}

return value + truncationString;
}
}
}
17 changes: 17 additions & 0 deletions src/Humanizer/Truncation/ITruncator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
namespace Humanizer
{
/// <summary>
/// Can truncate a string.
/// </summary>
public interface ITruncator
{
/// <summary>
/// Truncate a string
/// </summary>
/// <param name="value">The string to truncate</param>
/// <param name="length">The length to truncate to</param>
/// <param name="truncationString">The string used to truncate with</param>
/// <returns>The truncated string</returns>
string Truncate(string value, int length, string truncationString);
}
}
Loading