文字列を複数行にワードラップしようとしています。すべての行には幅が定義されています。
たとえば、幅120ピクセルの領域にワードラップすると、この結果が得られます。
Lorem ipsum dolor sit amet、
Conceptetur adipiscing elit。 Sed augue
ベロイト、一時的な非性的座位アメット、
dictum vitae lacus。ヴィテアンテで
justo、ut accumsan sem。ドネック
pulvinar、nisi nec sagittis consequat、
sem orci luctus velit、sed elementum
ligula ante nec neque。ペレンテスク
habitant morbi tristique senectus et
netus et malesuada fames ac turpis
egestas。エティアム・エラ・エスト、ペレンテスク
tincidunt ut、egestas in anteを取得します。
Nulla vitae vulputate velit。プロイン
congue neque。 Cras Rutrum Sodales
sapien、ut convallis erat auctor vel。
Duis ultricies pharetra dui、sagittis
varius mauris tristique a。ナム
neque id risus tempor hendrerit。
Maecenas ut lacus nunc。ヌラ
fermentum ornare rhoncus。ヌラ
gravida vestibulum odio、vel commodo
マグナ調味料quis。クィスク
sollicitudin blandit mi、非バリウス
リベロロボルティスeu。前庭eu
turpis massa、id tincidunt orci。
Curabitur pellentesque urna non risus
難解なファシリシス。モーリス・ベル
accumsan purus。 Proin quis enim nec
sem tempor vestibulum ac vitae augue。
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
ライブラリーを追加します。
この 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;
}
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();
}
ありがとう! as-cii Windowsフォームで使用するためのいくつかの変更を加えた答えから方法を取ります。 FormattedTextの代わりにTextRenderer.MeasureTextを使用:
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>ピクセルの場合、このWordは次の行にある必要があります。
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;
}
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();
}
テキストをラップして、後でイメージに描画したいと思います。 @ as-ciiから答えを試しましたが、私の場合は期待どおりに動作しませんでした。それは常に私の行の与えられた幅を拡張します(おそらく、それをGraphicsオブジェクトと組み合わせて使用して画像にテキストを描画するためです)。さらに、彼の答え(および関連するもの)は、.Net 4フレームワークに対してのみ有効です。フレームワーク.Net 3.5には、StringBuilderオブジェクトのClear()関数はありません。これが編集されたバージョンです:
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;
}
私はGraphicsオブジェクトを使用しているため、@ Thorinsソリューションを試しました。これはテキストを適切にラップするので、私にとってははるかにうまくいきました。ただし、メソッドに必要なパラメーターを指定できるように、いくつかの変更を加えました。また、バグがありました。forループのifブロックの条件に達していない場合、リストに最後の行が追加されませんでした。そのため、後でこの行を追加する必要があります。編集されたコードは次のようになります。
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;
}
MeasureString()メソッドを使用して、System.Drawing.Graphicsクラスから文字列の(おおよその)幅を取得できます。非常に正確な幅が必要な場合は、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;
}