Displaying The First n Characters Of Text

Displaying the first n characters of a block of text on a page without chopping words off halfway through is a common requirement. There are a number of ways to achieve this, but here's an extension method that you might find useful.
public static class StringExtensions
{
  /// <summary>
  /// Returns part of a string up to the specified number of characters, while maintaining full words
  /// </summary>
  /// <param name="s"></param>
  /// <param name="length">Maximum characters to be returned</param>
  /// <returns>String</returns>
  public static string Chop(this string s, int length)
  {
    if (String.IsNullOrEmpty(s))
      throw new ArgumentNullException(s);
    var words = s.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
    if (words[0].Length > length)
      return words[0];
    var sb = new StringBuilder();

    foreach (var word in words)
    {
      if ((sb + word).Length > length)
        return string.Format("{0}...", sb.ToString().TrimEnd(' '));
      sb.Append(word + " ");
    }
    return string.Format("{0}...", sb.ToString().TrimEnd(' '));
  }
}

In case you didn't know, an Extension method is one that appears to endow an existing type with additional methods. In this case, the type is System.String. The String type already comes with a large number of methods, together with an array of extensions methods provided by the .NET framework developers. Extension methods are static methods, which are called in the same way as instance methods although you don't instantiate an instance of the object that the method acts upon. The type that an extension method extend is denoted by the first parameter, and it's preceded by the this keyword. Here are some example of how to use this extension method:


[Razor]

@myString.Chop(50)



[MVC in a Web Forms View]

<%= ViewData["myString"].ToString().Chop(50) %>



[Web Forms in an ItemTemplate]

<ItemTemplate>
   <asp:Label ID="Label1" runat="server" Text='<%# Eval("myString").ToString().Chop(50) %>' />
</ItemTemplate>

A quick explanation about the body of the method itself - as I mentioned, the first parameter is the type which is intended to be extended, and the second is the maximum number of characters to be displayed. All the words in the string that this method acts on are placed as individual items in an array by the String.Split() method. StringSplitOptions.RemoveEmptyEntries ensures that if there are double spaces, they will not be treated as words and added to the array as elements. The array is iterated over in a foreach loop, and elements are added to a StringBuilder object (together with a space after each element or word). The LINQ expression checks the current length of the StringBuilder's contents on each iteration to ensure that the maximum length specified in the parameter is not exceeded. Finally, the result has the last trailing space removed (TrimEnd()), and is returned.

Date Posted: Sunday, May 16, 2010 9:59 AM
Last Updated: Wednesday, November 7, 2012 6:51 AM
Posted by: Mikesdotnetting
Total Views to date: 23043

13 Comments

Sunday, May 16, 2010 11:20 AM - Robert

Great extension. I added this method to my class with string extensions. Thanks

Monday, May 17, 2010 4:42 PM - Samuel

Very nice trick.

Thursday, May 20, 2010 9:15 PM - Sinden

I've been banging my head around a way to do this and got tied up in attempting to use Regex for it and it's as simple as this!

I don't know whether to be annoyed or grateful to you!

Sunday, September 26, 2010 5:25 PM - Pham Anh

Thanks you! Sharing

Thursday, January 27, 2011 9:51 PM - Javier

Thanks Mike for sharing this code. I added a little 'tidbit' that makes the dots appear ONLY if the string is indeed truncated. Say I have two strings, one is 25 characters and the other 50. My "Chop" is set at 40, so in the case of the 25 character string I don't want to see the dots, but in the 50 character string I do.

I had trouble posting the code here (for good reason, I don't think this form allows markup), so I've posted it as a follow-up to a post at the ASP.NET forums. Follow this link: http://forums.asp.net/t/1646631.aspx

Hope that helps someone out there.
Thanks again Mike for this great resource and all your code samples.

Wednesday, March 23, 2011 11:55 AM - Anooj

Shouldn't it be
if ((sb + word).Length > length)
instead of
if ((sb + word).Length + word.Length > length)
to get the desired result.

Anyways,it's a nice piece of code....

Thursday, March 24, 2011 8:14 PM - Mike

@Anooj

You are right, of course. The original version I posted appended word to the StringBuilder before the length was tested. I didn't update the length test at that time. I have now. Thanks.

Thursday, June 16, 2011 12:13 PM - somasekhar akiri

thanks mike nice article and nice extension method

Tuesday, August 14, 2012 6:16 PM - Tara

Thanks for this - just what I needed!

Sunday, October 14, 2012 4:10 PM - Jay Tsultim

How would I include this in a cshtml file aka razor

Sunday, October 14, 2012 5:25 PM - Mike

@Jay,

Copy the code into a C# class files (ends with .cs) and save it in an App_Code folder.

Monday, November 19, 2012 10:50 AM - Cat

I'm using vb .net. I copied your code into a new class and it works great if I call it with a button from a datalist but when I append <%# Eval("myString").ToString().Chop(50) %> into my html, I get an error 'Chop' is not a member of 'String'. Am I missing something obvious? Ideally, I want the truncation to execute on initialisation of the datalist so that when the user clicks a "More Details" button, I can display the full record. Any advice you can give would be greatly appreciated.

Saturday, March 1, 2014 3:53 PM - Darwin

I normally take the code and run. But I have to stop here and say this is an awesome implementation. I was going to trim in the controller and then pass this to the view. But this is a much better approach. I did not know this could be done in this fashion.
Nice work.
Add your comment

If you have any comments to make about this article, please use this form to do so. Make sure that your comment relates specifically to the article above. More general comments can be posted through the form on the Contact page.

Please note, all comments are moderated, and some may not be published. The kind of things that will ensure your comment is deleted without ever seeing the light of day are as follows:

  • Not relevant to the article
  • Gratuitous links to your own site or product
  • Anything abusive or libellous
  • Spam
  • Anything in a language I don't understand including gibberish.

I do not pass email addresses on to spammers, so a valid one will assist me in responding to you personally if required.

Recent Comments

Gautam 11/20/2014 8:01 AM
In response to I'm Writing A Book On WebMatrix
Hello Mike, I read your book, loved it! However, I have a few request/suggestions: 1) an example...

Bret Dev 11/19/2014 8:39 PM
In response to The Difference Between @Helpers and @Functions In WebMatrix
Excellent post! One concern - where can you place global @Functions code within an MVC project to Is...

Rob Farquharson 11/19/2014 4:28 PM
In response to iTextSharp - Links and Bookmarks
How can I place text at an absolute position on the page? Also, how can I rotate text?...

Andy 11/17/2014 8:08 PM
In response to MVC 5 with EF 6 in Visual Basic - Sorting, Filtering and Paging
Hello I'm testing your sorting instructions above. This is great and I was able to get it to work...

Gautam 11/17/2014 5:51 PM
In response to WebMatrix - Database Helpers for IN Clauses
Hi Mike, I am very new to programming: In the above example if I want to use a delete button the...

donramon 11/17/2014 3:22 PM
In response to Entity Framework 6 Recipe - Alphabetical Paging In ASP.NET MVC
Congratulations on your new website look and the excellent articles. Thank you!...

Gautam 11/17/2014 11:26 AM
In response to Looking At The WebMatrix WebGrid
Hi Mike, I add the jquery script at the end of my html file.. when ajax attribute is added to the be...

Chet Ripley 11/15/2014 6:57 PM
In response to Adding A New Field
It appears the command is case sensitive. I had the same issue as Cameron. When I changed the to it...

Alvin 11/14/2014 12:49 PM
In response to Razor Web Pages E-Commerce - Adding A Shopping Cart To The Bakery Template Site
Great article Mike! When do you plan to extend the bakery shopping cart beyond this point?...

Gautam 11/14/2014 10:16 AM
In response to Web Pages - Efficient Paging Without The WebGrid
to get the count can we use only the below sql, why to join category and author table var sql =...