Word обернуть строку в несколько строк - PullRequest
36 голосов
/ 18 октября 2010

Я пытаюсь переносить слова в несколько строк. Каждая строка будет иметь определенную ширину.

Например, я получил бы этот результат, если бы обернул его в область шириной 120 пикселей.

Lorem ipsum dolor sit amet,
Concectetur Adipiscing Elit. Sed augue
велит, темпор не вульпутат сит амет,
Биография Lacus. In Vitae Ante
justo, ut accumsan sem. Донец
pulvinar, nisi nec sagittis consquat,
sem orci luctus Velit, sed elementum
ligula ante nec neque. Pellentesque
житель морби тристик сенект и др.
Netus et malesuada Fames AC Turpis
экскреты. Etiam erat est, pellentesque
eget tincidunt ut, egestas in ante.
Nulla vitae vulputate velit. Проин в
конгу некэ. Cras rutrum sodales
sapien, ut convallis erat auctor vel.
Duis ultricies pharetra dui, sagittis
Вариус Маурис Тристик а. Нам ут
neque id risus tempor hendrerit.
Меценат ут лакун нун. Nulla
fermentum ornare rhoncus. Nulla
Gravida vestibulum odio, Vel Goodso
Magna Condimentum Quis. Quisque
sollicitudin blandit mi, non varius
Либеро Лобортис ЕС. Вестибюль ЕС
turpis massa, id tincidunt orci.
Курабитур пеллетеская урна не рисус
жировой спазм. Mauris vel
Accumsan Purus. Proin quis enim nec
sem tempor vestibulum ac vitae augue.

Ответы [ 8 ]

38 голосов
/ 18 октября 2010
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;
        }
    }

    if(actualLine.Length > 0)
        wrappedLines.Add(actualLine.ToString());

    return wrappedLines;
}

Добавить WindowsBase и PresentationCore библиотеки.

20 голосов
/ 18 октября 2010

Следующий код, взятый из этого blogpost , поможет выполнить вашу работу.

Вы можете использовать его следующим образом:

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

Обратите вниманиечто код не мой, я просто сообщаю здесь основную функцию для вашего товара.

protected const string _newline = "\r\n";

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();
}

/// <summary>
/// Locates position to break the given line so as to avoid
/// breaking words.
/// </summary>
/// <param name="text">String that contains line of text</param>
/// <param name="pos">Index where line of text starts</param>
/// <param name="max">Maximum line length</param>
/// <returns>The modified line length</returns>
public static int BreakLine(string text, int pos, int max)
{
  // Find last whitespace in line
  int i = max - 1;
  while (i >= 0 && !Char.IsWhiteSpace(text[pos + i]))
    i--;
  if (i < 0)
    return max; // No whitespace found; break at maximum length
  // Find start of whitespace
  while (i >= 0 && Char.IsWhiteSpace(text[pos + i]))
    i--;
  // Return length of text before whitespace
  return i + 1;
}
5 голосов
/ 11 октября 2013

Вот версия, которую я придумал для своей игры XNA ...

(Обратите внимание, что это фрагмент, а не правильное определение класса. Наслаждайтесь!)

using System;
using System.Text;
using Microsoft.Xna.Framework.Graphics;

public static float StringWidth(SpriteFont font, string text)
{
    return font.MeasureString(text).X;
}

public static string WrapText(SpriteFont font, string text, float lineWidth)
{
    const string space = " ";
    string[] words = text.Split(new string[] { space }, StringSplitOptions.None);
    float spaceWidth = StringWidth(font, space),
        spaceLeft = lineWidth,
        wordWidth;
    StringBuilder result = new StringBuilder();

    foreach (string word in words)
    {
        wordWidth = StringWidth(font, word);
        if (wordWidth + spaceWidth > spaceLeft)
        {
            result.AppendLine();
            spaceLeft = lineWidth - wordWidth;
        }
        else
        {
            spaceLeft -= (wordWidth + spaceWidth);
        }
        result.Append(word + space);
    }

    return result.ToString();
}
3 голосов
/ 23 апреля 2016

Спасибо! Я использую метод ответа as-cii с некоторыми изменениями для использования в формах Windows. Использование TextRenderer.MeasureText вместо FormattedText :

static List<string> WrapText(string text, double pixels, Font font)
{
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)
{
    int w = TextRenderer.MeasureText(item + " ", font).Width;
    actualWidth += w;

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

    actualLine.Append(item + " ");
}

if(actualLine.Length > 0)
    wrappedLines.Add(actualLine.ToString());

return wrappedLines;
}

И небольшое замечание: строку actualLine.Append (item + ""); необходимо разместить после проверки ширины, потому что, если actualWidth> пикселей, это слово должно быть в следующей строке.

1 голос
/ 15 апреля 2016

Для Winforms:

List<string> WrapText(string text, int maxWidthInPixels, Font font)
{
    string[] originalLines = text.Split(new string[] { " " }, StringSplitOptions.None);

    List<string> wrappedLines = new List<string>();

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

    foreach (var item in originalLines)
    {
        Size szText = TextRenderer.MeasureText(item, font);

        actualLine.Append(item + " ");
        actualWidth += szText.Width;

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

    if (actualLine.Length > 0)
        wrappedLines.Add(actualLine.ToString());

    return wrappedLines;
}
0 голосов
/ 24 марта 2017

Я хотел обернуть текст, чтобы потом нарисовать его на своем изображении.Я попробовал ответ от @ as-cii, но в моем случае это не сработало, как ожидалось.Он всегда расширяет заданную ширину моей линии (возможно, потому что я использую ее в сочетании с объектом Graphics для рисования текста в моем изображении).Кроме того, его ответ (и связанные с ним) просто работают для> .Net 4 фреймворков.В рамках .Net 3.5 отсутствует функция Clear () для StringBuilder объектов.Итак, вот отредактированная версия:

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

        List<string> wrappedLines = new List<string>();

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

        foreach (string word in originalWords)
        {
            string wordWithSpace = word + " ";
            FormattedText formattedWord = new FormattedText(wordWithSpace,
                CultureInfo.CurrentCulture,
                System.Windows.FlowDirection.LeftToRight,
                new Typeface(fontFamily), emSize, System.Windows.Media.Brushes.Black);

            actualLine.Append(wordWithSpace);
            actualWidth += formattedWord.Width;

            if (actualWidth > pixels)
            {
                actualLine.Remove(actualLine.Length - wordWithSpace.Length, wordWithSpace.Length);
                wrappedLines.Add(actualLine.ToString());
                actualLine = new StringBuilder();
                actualLine.Append(wordWithSpace);
                actualWidth = 0;
                actualWidth += formattedWord.Width;
            }
        }

        if (actualLine.Length > 0)
            wrappedLines.Add(actualLine.ToString());

        return wrappedLines;
    }

Поскольку я работаю с графическим объектом, я попробовал решение @Thorins.Это сработало для меня намного лучше, так как правильно оборачивает текст.Но я внес некоторые изменения, чтобы вы могли дать методу необходимые параметры.Также была ошибка: последняя строка не была добавлена ​​в список, когда не было выполнено условие блока if в цикле for.Таким образом, вы должны добавить эту строку позже.Отредактированный код выглядит так:

    public static List<string> WrapTextWithGraphics(Graphics g, string original, int width, Font font)
    {
        List<string> wrappedLines = new List<string>();

        string currentLine = string.Empty;

        for (int i = 0; i < original.Length; i++)
        {
            char currentChar = original[i];
            currentLine += currentChar;
            if (g.MeasureString(currentLine, font).Width > width)
            {
                // 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);
                wrappedLines.Add(lineToAdd);
                currentLine = string.Empty;
            }
        }

        if (currentLine.Length > 0)
            wrappedLines.Add(currentLine);

        return wrappedLines;
    }
0 голосов
/ 12 мая 2013
public static string GetTextWithNewLines(string value = "", int charactersToWrapAt = 35, int maxLength = 250)
        {
            if (string.IsNullOrWhiteSpace(value)) return "";

            value = value.Replace("  ", " ");
            var words = value.Split(' ');
            var sb = new StringBuilder();
            var currString = new StringBuilder();

            foreach (var word in words)
            {
                if (currString.Length + word.Length + 1 < charactersToWrapAt) // The + 1 accounts for spaces
                {
                    sb.AppendFormat(" {0}", word);
                    currString.AppendFormat(" {0}", word);
                }
                else
                {
                    currString.Clear();
                    sb.AppendFormat("{0}{1}", Environment.NewLine, word);
                    currString.AppendFormat(" {0}", word);
                }
            }

            if (sb.Length > maxLength)
            {
                return sb.ToString().Substring(0, maxLength) + " ...";
            }

            return sb.ToString().TrimStart().TrimEnd();
        }
0 голосов
/ 18 октября 2010

Вы можете получить (приблизительную) ширину строки из класса System.Drawing.Graphics с помощью метода MeasureString (). Если вам нужна очень точная ширина, я думаю, что вы должны использовать метод MeasureCharacterRanges (). Вот пример кода, использующего метод MeasureString (), чтобы примерно выполнить то, что вы просили:

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;
}
...