Truncate string on whole words in .NET C#

C#.NetStringTruncate

C# Problem Overview


I am trying to truncate some long text in C#, but I don't want my string to be cut off part way through a word. Does anyone have a function that I can use to truncate my string at the end of a word?

E.g:

"This was a long string..."

Not:

"This was a long st..."

C# Solutions


Solution 1 - C#

Try the following. It is pretty rudimentary. Just finds the first space starting at the desired length.

public static string TruncateAtWord(this string value, int length) {
    if (value == null || value.Length < length || value.IndexOf(" ", length) == -1)
        return value;

    return value.Substring(0, value.IndexOf(" ", length));
}

Solution 2 - C#

Thanks for your answer Dave. I've tweaked the function a bit and this is what I'm using ... unless there are any more comments ;)

public static string TruncateAtWord(this string input, int length)
{
	if (input == null || input.Length < length)
		return input;
	int iNextSpace = input.LastIndexOf(" ", length, StringComparison.Ordinal);
	return string.Format("{0}…", input.Substring(0, (iNextSpace > 0) ? iNextSpace : length).Trim());
}

Solution 3 - C#

My contribution:

public static string TruncateAtWord(string text, int maxCharacters, string trailingStringIfTextCut = "&hellip;")
{
    if (text == null || (text = text.Trim()).Length <= maxCharacters) 
      return text;

    int trailLength = trailingStringIfTextCut.StartsWith("&") ? 1 
                                                              : trailingStringIfTextCut.Length; 
    maxCharacters = maxCharacters - trailLength >= 0 ? maxCharacters - trailLength 
                                                     : 0;
    int pos = text.LastIndexOf(" ", maxCharacters);
    if (pos >= 0)
        return text.Substring(0, pos) + trailingStringIfTextCut;

    return string.Empty;
}

This is what I use in my projects, with optional trailing. Text will never exceed the maxCharacters + trailing text length.

Solution 4 - C#

If you are using windows forms, in the Graphics.DrawString method, there is an option in StringFormat to specify if the string should be truncated, if it does not fit into the area specified. This will handle adding the ellipsis as necessary.

http://msdn.microsoft.com/en-us/library/system.drawing.stringtrimming.aspx

Solution 5 - C#

I took your approach a little further:

public string TruncateAtWord(string value, int length)
{
	if (value == null || value.Trim().Length <= length)
		return value;

	int index = value.Trim().LastIndexOf(" ");

	while ((index + 3) > length)
		index = value.Substring(0, index).Trim().LastIndexOf(" ");
	
	if (index > 0)
		return value.Substring(0, index) + "...";

	return value.Substring(0, length - 3) + "...";
}

I'm using this to truncate tweets.

Solution 6 - C#

This solution works too (takes first 10 words from myString):

String.Join(" ", myString.Split(' ').Take(10))

Solution 7 - C#

Taking into account more than just a blank space separator (e.g. words can be separated by periods followed by newlines, followed by tabs, etc.), and several other edge cases, here is an appropriate extension method:

    public static string GetMaxWords(this string input, int maxWords, string truncateWith = "...", string additionalSeparators = ",-_:")
    {
        int words = 1;
        bool IsSeparator(char c) => Char.IsSeparator(c) || additionalSeparators.Contains(c);

        IEnumerable<char> IterateChars()
        {
            yield return input[0];

            for (int i = 1; i < input.Length; i++)
            {
                if (IsSeparator(input[i]) && !IsSeparator(input[i - 1]))
                    if (words == maxWords)
                    {
                        foreach (char c in truncateWith)
                            yield return c;

                        break;
                    }
                    else
                        words++;

                yield return input[i];
            }
        }

        return !input.IsNullOrEmpty()
            ? new String(IterateChars().ToArray())
            : String.Empty;
    }

Solution 8 - C#

simplified, added trunking character option and made it an extension.

    public static string TruncateAtWord(this string value, int maxLength)
    {
        if (value == null || value.Trim().Length <= maxLength)
            return value;

        string ellipse = "...";
        char[] truncateChars = new char[] { ' ', ',' };
        int index = value.Trim().LastIndexOfAny(truncateChars);
        
        while ((index + ellipse.Length) > maxLength)
            index = value.Substring(0, index).Trim().LastIndexOfAny(truncateChars);

        if (index > 0)
            return value.Substring(0, index) + ellipse;

        return value.Substring(0, maxLength - ellipse.Length) + ellipse;
    }

Solution 9 - C#

Heres what i came up with. This is to get the rest of the sentence also in chunks.

public static List<string> SplitTheSentenceAtWord(this string originalString, int length)
    {
        try
        {
            List<string> truncatedStrings = new List<string>();
            if (originalString == null || originalString.Trim().Length <= length)
            {
                truncatedStrings.Add(originalString);
                return truncatedStrings;
            }
            int index = originalString.Trim().LastIndexOf(" ");

            while ((index + 3) > length)
                index = originalString.Substring(0, index).Trim().LastIndexOf(" ");

            if (index > 0)
            {
                string retValue = originalString.Substring(0, index) + "...";
                truncatedStrings.Add(retValue);

                string shortWord2 = originalString;
                if (retValue.EndsWith("..."))
                {
                    shortWord2 = retValue.Replace("...", "");
                }
                shortWord2 = originalString.Substring(shortWord2.Length);

                if (shortWord2.Length > length) //truncate it further
                {
                    List<string> retValues = SplitTheSentenceAtWord(shortWord2.TrimStart(), length);
                    truncatedStrings.AddRange(retValues);
                }
                else
                {
                    truncatedStrings.Add(shortWord2.TrimStart());
                }
                return truncatedStrings;
            }
            var retVal_Last = originalString.Substring(0, length - 3);
            truncatedStrings.Add(retVal_Last + "...");
            if (originalString.Length > length)//truncate it further
            {
                string shortWord3 = originalString;
                if (originalString.EndsWith("..."))
                {
                    shortWord3 = originalString.Replace("...", "");
                }
                shortWord3 = originalString.Substring(retVal_Last.Length);
                List<string> retValues = SplitTheSentenceAtWord(shortWord3.TrimStart(), length);

                truncatedStrings.AddRange(retValues);
            }
            else
            {
                truncatedStrings.Add(retVal_Last + "...");
            }
            return truncatedStrings;
        }
        catch
        {
            return new List<string> { originalString };
        }
    }

Solution 10 - C#

I use this

public string Truncate(string content, int length)
    {
        try
        {
            return content.Substring(0,content.IndexOf(" ",length)) + "...";
        }
        catch
        {
            return content;
        }
    }

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionTimSView Question on Stackoverflow
Solution 1 - C#DavidView Answer on Stackoverflow
Solution 2 - C#TimSView Answer on Stackoverflow
Solution 3 - C#ContraView Answer on Stackoverflow
Solution 4 - C#mlsteevesView Answer on Stackoverflow
Solution 5 - C#Douglas LudlowView Answer on Stackoverflow
Solution 6 - C#user1795248View Answer on Stackoverflow
Solution 7 - C#SysCafeView Answer on Stackoverflow
Solution 8 - C#Leon van WykView Answer on Stackoverflow
Solution 9 - C#Rahul SonthaliaView Answer on Stackoverflow
Solution 10 - C#Zhou HaiView Answer on Stackoverflow