views:

53

answers:

4

I am trying to word wrap a string into multiple lines whit every line respecting a defined width.

For example word wrap the following text to fit an area of 120 pixels in width.

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed augue velit, tempor non vulputate sit amet, dictum vitae lacus. In vitae ante justo, ut accumsan sem. Donec pulvinar, nisi nec sagittis consequat, sem orci luctus velit, sed elementum ligula ante nec neque. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Etiam erat est, pellentesque eget tincidunt ut, egestas in ante. Nulla vitae vulputate velit. Proin in congue neque. Cras rutrum sodales sapien, ut convallis erat auctor vel. Duis ultricies pharetra dui, sagittis varius mauris tristique a. Nam ut neque id risus tempor hendrerit. Maecenas ut lacus nunc. Nulla fermentum ornare rhoncus. Nulla gravida vestibulum odio, vel commodo magna condimentum quis. Quisque sollicitudin blandit mi, non varius libero lobortis eu. Vestibulum eu turpis massa, id tincidunt orci. Curabitur pellentesque urna non risus adipiscing facilisis. Mauris vel accumsan purus. Proin quis enim nec sem tempor vestibulum ac vitae augue.

I am using C#.

A: 

The following code, taken from this blogpost, will help to get your job done.

You can use it this way:

string wordWrappedText = WordWrap( <yourtext>, 120 );

Please note that the code is not mine, I am just reporting here the main function for your commodity.

public static string WordWrap( string the_string, int width ) {
    int pos, next;
    StringBuilder sb = new StringBuilder();

    // Lucidity check
    if ( width < 1 )
        return the_string;

    // Parse each line of text
    for ( pos = 0; pos < the_string.Length; pos = next ) {
        // Find end of line
        int eol = the_string.IndexOf( _newline, pos );

        if ( eol == -1 )
            next = eol = the_string.Length;
        else
            next = eol + _newline.Length;

        // Copy this line of text, breaking into smaller lines as needed
        if ( eol > pos ) {
            do {
                int len = eol - pos;

                if ( len > width )
                    len = BreakLine( the_string, pos, width );

                sb.Append( the_string, pos, len );
                sb.Append( _newline );

                // Trim whitespace following break
                pos += len;

                while ( pos < eol && Char.IsWhiteSpace( the_string[pos] ) )
                    pos++;

            } while ( eol > pos );
        } else sb.Append( _newline ); // Empty line
    }

    return sb.ToString();
}
Lorenzo
That looks like width in characters, not in pixels.
Albin Sunnanbo
Oooops.... you're right! read too fast...
Lorenzo
A: 

What type of control contains the text? There are a number of controls you could extend to take advantage of the built-in text wrapping

James B
This is a comment, not an answer. However, my guess is this might have something to do with image or PDF rendering.
Anthony Pegram
It's an Image. Can't vote but +1 for Anthony Pegram
ForrestWhy
+3  A: 
static void Main(string[] args)
    {
        List<string> lines = WrapText("Add some text", 300, "Calibri", 11);

        foreach (var item in lines)
        {
            Console.WriteLine(item);
        }


        Console.ReadLine();
    }

    static List<string> WrapText(string text, double pixels, string fontFamily, float emSize)
    {
        string[] originalLines = text.Split(new string[] { " " }, StringSplitOptions.None);
        List<string> wrappedLines = new List<string>();

        StringBuilder actualLine = new StringBuilder();
        double actualWidth = 0;

        foreach (var item in originalLines)
        {
            FormattedText formatted = new FormattedText(item, CultureInfo.CurrentCulture, System.Windows.FlowDirection.LeftToRight,
                                      new Typeface(fontFamily), emSize, Brushes.Black);
            actualLine.Append(item + " ");
            actualWidth += formatted.Width;

            if (actualWidth > pixels)
            {
                wrappedLines.Add(actualLine.ToString());
                actualLine.Clear();
                actualWidth = 0;
            }
        }

        return wrappedLines;
    }

Add WindowsBase and PresentationCore libraries.

AS-CII
@AS-CII: Thanks a lot!!!
ForrestWhy
Better than my answer. Nice one, AS-CII.
Thorin
A: 

You can get the (approximate) width of a string from the System.Drawing.Graphics class using the MeasureString() method. If you need a very precise width, I think you have to use the MeasureCharacterRanges() method. Here is some sample code using the MeasureString() method to do roughly what you asked for:

using System;
using System.Collections.Generic; // for List<>
using System.Drawing; // for Graphics and Font

private List<string> GetWordwrapped(string original)
{
    List<string> wordwrapped = new List<string>();

    Graphics graphics = Graphics.FromHwnd(this.Handle);
    Font font = new Font("Arial", 10);

    string currentLine = string.Empty;

    for (int i = 0; i < original.Length; i++)
    {
        char currentChar = original[i];
        currentLine += currentChar;
        if (graphics.MeasureString(currentLine, font).Width > 120)
        {
            // exceeded length, back up to last space
            int moveback = 0;
            while (currentChar != ' ')
            {
                moveback++;
                i--;
                currentChar = original[i];
            }
            string lineToAdd = currentLine.Substring(0, currentLine.Length - moveback);
            wordwrapped.Add(lineToAdd);
            currentLine = string.Empty;
        }
    }

    return wordwrapped;
}
Thorin