2010-10-18 13 views
31

01 a.m. tratando de palabra envolver una cadena en varias líneas. Cada líneas se han definido anchura.ajuste de línea en una cadena de múltiples líneas

Por ejemplo, si 1 1 sería conseguir este canal de resultado envuelve a un área de 120 píxeles de ancho.

zanahorias de Lorem Ipsum, tomate
investigación de pregrado.
sed velita augue, vulputate sit amet tempor no lo hizo, se dijo
del estrés de la vida. En frente de
tan ensalada capa. Hasta
almohada, ni sed eros tempor, excepto,
sem luctus Orci velita, sed elementum ligula priori, ninguno, ni
. Nutrición
residentes de fútbol triste viejo y feo

Netus et malesuada hambre y la pobreza. Incluso allí, los niños necesitan
desarrolladores podrían querer por adelantado.
sin vida al aire libre Vulputate. Proin en
Vivamus lorem. miembros de maquillaje mañana
sapiens al autor o al valle.
ultricies tarea dui carcaj, flechas
de diversos adipiscing. Para que usted pueda
ñeque hendrerit Identificación RISUS tempor.
Mecenas lago ahora. Sin
de fútbol naranja caliente. Sin
odio de fabricación embarazada o conveniencia
con cualquier salsa. Cada
sientan mi cuidado no se varía
libre del cartón del fútbol. Fútbol del
fea masa, que los desarrolladores clínicos.
olla nutrición de chat no sonríe
antioxidantes de grado. Moors, o
rodajas de capa. El porche y la vida que no es ni siquiera
sem tempor Proin quis augue.

+1

¿Cómo le gustaría que fuera el resultado? A una variedad de cadenas? O cadenas impresas en un mapa de bits? ¿Qué tipo de letra y tamaño usas? –

+0

¡Una serie de cadenas debería ser buena! – ForrestWhy

+0

No olvides pensar qué hacer si tienes texto que no tiene espacios para 120 píxeles. – Thorin

Respuesta

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

Añadir WindowsBasePresentationCore y bibliotecas.

+0

¿Alguna experiencia hasta ahora? ¿Cuánta medición de 'FormattedText' concuerda con la representación del texto de WinForms (usando' Graphics.DrawString'or 'TextRenderer.DrawText')? – floele

17

el siguiente código, tomado de esta blogpost, ayudará a hacer su trabajo.

Usted puede usarlo de esta manera:

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

Tenga en cuenta que el código no es mía, 01 a.m. sólo un informe de aquí la función principal para su comodidad.

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; 
} 
+1

Tiene el mismo ancho que los caracteres, no en píxeles. –

+0

Oooops ... ¡tienes razón! lea demasiado rápido ... – Lorenzo

0

Usted puede obtener la anchura (aproximado) de una cadena de la clase System.Drawing.Graphics utilizando el método MeasureString(). Si necesita un ancho muy preciso, 1 creo que hay que utilizar los MeasureCharacterRanges método().Aquí hay un código de ejemplo utilizando el método MeasureString() para hacer más o menos lo que pidieron:

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

Aquí hay una versión que se me ocurrió para mi juego XNA ...

(Tenga en cuenta que que es un fragmento, no una definición de clase adecuada Disfruta)

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

Para Windows Forms:.!

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

Gracias! Tomo el método de as-cii responder con algunos cambios, para usarlo en formularios de Windows. Usando TextRenderer.MeasureText en lugar de 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; 
} 

Y un poco de observación: la línea actualLine.Append (artículo + " "); debe colocarse después de comprobar el ancho, ya que si realWidth> píxeles, esta palabra debe estar en la siguiente línea.

0

Me gustaría envolver texto para dibujarlo después en mi imagen. Intenté la respuesta de @ as-cii, pero no funcionó en mi caso como se esperaba. Siempre se extiende el ancho dado de mi línea (tal vez porque lo uso en combinación con un objeto Graphics para dibujar el texto en mi imagen). Además, su respuesta (y las relacionadas) solo funcionan para> .Net 4 frameworks. En Framework .Net 3.5 no hay función Clear() para StringBuilder objetos. Así que aquí está una versión editada:

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

Como estoy trabajando con un objeto Graphics probé la solución @Thorins. Esto funcionó mucho mejor para mí, ya que envuelve mi texto correctamente. Pero hice algunos cambios para que pueda darle al método los parámetros requeridos. También hubo un error: la última línea no se agregó a la lista, cuando no se alcanzó la condición del bloque if en for-loop. Entonces debes agregar esta línea después. El código editado se ve así:

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; 
    } 
Cuestiones relacionadas