Word racchiude una stringa in più righe

Sto cercando di racchiudere una stringa in più righe. Ogni linea avrà una larghezza definita.

Ad esempio, otterrei questo risultato se la parola fosse racchiusa in un’area di 120 pixel di larghezza.

Lorem ipsum dolor sit amet,
consectetur adipiscing elit. Sed
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
abitante 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
vari mauris tristique a. Nam ut
neque id risus tempor hendrerit.
Mecenate ut lac nunc. nulla
fermentum ornare rhoncus. nulla
gravida vestibulum odio, vel commodo
magna condimento. Quisque
sollicitudin blandit mi, non varius
libero lobortis eu. Vestibulum eu
turpis massa, id tincidunt orci.
Curabitur pellentesque urna non risus
facilità di adipiscing. Mauris vel
accumsan purus. Proin quis enim nec
sem temporale vestibulum ac vitae augue.

static void Main(string[] args) { List lines = WrapText("Add some text", 300, "Calibri", 11); foreach (var item in lines) { Console.WriteLine(item); } Console.ReadLine(); } static List WrapText(string text, double pixels, string fontFamily, float emSize) { string[] originalLines = text.Split(new string[] { " " }, StringSplitOptions.None); List wrappedLines = new List(); 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; } 

Aggiungi le librerie WindowsBase e PresentationCore .

Il seguente codice, tratto da questo blogpost , ti aiuterà a portare a termine il tuo lavoro.

Puoi usarlo in questo modo:

 string wordWrappedText = WordWrap( , 120 ); 

Si prega di notare che il codice non è mio, sto solo riportando qui la funzione principale per la vostra merce.

 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(); } ///  /// Locates position to break the given line so as to avoid /// breaking words. ///  /// String that contains line of text /// Index where line of text starts /// Maximum line length /// The modified line length 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; } 

Ecco una versione che mi è venuta in mente per il mio gioco XNA …

(Nota che è uno snippet, non una definizione di class corretta. Divertiti!)

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

Grazie! Prendo il metodo dalla risposta as-cii con alcune modifiche, per usarlo in Windows Form. Utilizzando TextRenderer.MeasureText anziché FormattedText :

 static List WrapText(string text, double pixels, Font font) { string[] originalLines = text.Split(new string[] { " " }, StringSplitOptions.None); List wrappedLines = new List(); 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; } 

E una piccola osservazione: la riga actualLine.Append (item + “”); deve essere posizionato dopo aver controllato la larghezza, perché se actualWidth> pixels, questa parola deve essere nella riga successiva.

Per Winforms:

 List WrapText(string text, int maxWidthInPixels, Font font) { string[] originalLines = text.Split(new string[] { " " }, StringSplitOptions.None); List wrappedLines = new List(); 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; } 

È ansible ottenere la larghezza (approssimativa) di una stringa dalla class System.Drawing.Graphics mediante il metodo MeasureString (). Se hai bisogno di una larghezza molto precisa, penso che devi usare il metodo MeasureCharacterRanges (). Ecco alcuni esempi di codice che usano il metodo MeasureString () per fare approssimativamente ciò che hai chiesto:

 using System; using System.Collections.Generic; // for List<> using System.Drawing; // for Graphics and Font private List GetWordwrapped(string original) { List wordwrapped = new List(); 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; } 
 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(); } 

Mi piacerebbe avvolgere il testo per disegnarlo in seguito nella mia immagine. Ho provato la risposta da @ as-cii, ma nel mio caso non ha funzionato come previsto. Estende sempre la larghezza data della mia linea (forse perché la uso in combinazione con un object Graphics per disegnare il testo nella mia immagine). Inoltre la sua risposta (e quelle relative) funzionano solo per i framework .Net 4. Nel framework .Net 3.5 non esiste alcuna funzione Clear () per gli oggetti StringBuilder . Quindi ecco una versione modificata:

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

Poiché sto lavorando con un object Graphics, ho provato la soluzione @Thorins. Questo ha funzionato per me molto meglio, poiché avvolge correttamente il mio testo. Ma ho apportato alcune modifiche in modo da poter fornire al metodo i parametri richiesti. Inoltre c’è stato un bug: l’ultima riga non è stata aggiunta alla lista, quando non è stata raggiunta la condizione del blocco if nel ciclo for. Quindi devi aggiungere questa riga in seguito. Il codice modificato assomiglia a:

  public static List WrapTextWithGraphics(Graphics g, string original, int width, Font font) { List wrappedLines = new List(); 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; }