我需要在某个区域内写出不同的文字段落。例如,我在控制台上画了一个如下所示的框:
/----------------------\
| |
| |
| |
| |
\----------------------/
如何在其中书写文字,但如果篇幅太长,请将其换行到下一行?
答案 0 :(得分:11)
在行长之前的最后一个空格上拆分?
int myLimit = 10;
string sentence = "this is a long sentence that needs splitting to fit";
string[] words = sentence.Split(new char[] { ' ' });
IList<string> sentenceParts = new List<string>();
sentenceParts.Add(string.Empty);
int partCounter = 0;
foreach (string word in words)
{
if ((sentenceParts[partCounter] + word).Length > myLimit)
{
partCounter++;
sentenceParts.Add(string.Empty);
}
sentenceParts[partCounter] += word + " ";
}
foreach (string x in sentenceParts)
Console.WriteLine(x);
更新(上述解决方案在某些情况下失去了最后一个字):
int myLimit = 10;
string sentence = "this is a long sentence that needs splitting to fit";
string[] words = sentence.Split(' ');
StringBuilder newSentence = new StringBuilder();
string line = "";
foreach (string word in words)
{
if ((line + word).Length > myLimit)
{
newSentence.AppendLine(line);
line = "";
}
line += string.Format("{0} ", word);
}
if (line.Length > 0)
newSentence.AppendLine(line);
Console.WriteLine(newSentence.ToString());
答案 1 :(得分:2)
我修改了Jim H的版本,以便它支持一些特殊情况。 例如,句子不包含任何空白字符的情况;我还注意到,当一条线在最后一个位置有一个空格时会出现问题;然后在最后添加空格,你最终得到一个字符。
这是我的版本,以防有人感兴趣:
public static List<string> WordWrap(string input, int maxCharacters)
{
List<string> lines = new List<string>();
if (!input.Contains(" "))
{
int start = 0;
while (start < input.Length)
{
lines.Add(input.Substring(start, Math.Min(maxCharacters, input.Length - start)));
start += maxCharacters;
}
}
else
{
string[] words = input.Split(' ');
string line = "";
foreach (string word in words)
{
if ((line + word).Length > maxCharacters)
{
lines.Add(line.Trim());
line = "";
}
line += string.Format("{0} ", word);
}
if (line.Length > 0)
{
lines.Add(line.Trim());
}
}
return lines;
}
答案 2 :(得分:2)
我修改了Manfred的版本。如果你把一个字符串放在&#39; \ n&#39;它中的字符,它将奇怪地包装文本,因为它会将其视为另一个字符。通过这一微小的改变,一切都会顺利进行。
public static List<string> WordWrap(string input, int maxCharacters)
{
List<string> lines = new List<string>();
if (!input.Contains(" ") && !input.Contains("\n"))
{
int start = 0;
while (start < input.Length)
{
lines.Add(input.Substring(start, Math.Min(maxCharacters, input.Length - start)));
start += maxCharacters;
}
}
else
{
string[] paragraphs = input.Split('\n');
foreach (string paragraph in paragraphs)
{
string[] words = paragraph.Split(' ');
string line = "";
foreach (string word in words)
{
if ((line + word).Length > maxCharacters)
{
lines.Add(line.Trim());
line = "";
}
line += string.Format("{0} ", word);
}
if (line.Length > 0)
{
lines.Add(line.Trim());
}
}
}
return lines;
}
答案 3 :(得分:2)
我从Jim H.'s solution开始,最终得到了这种方法。唯一的问题是文本是否有任何超过限制的单词。但效果很好。
public static List<string> GetWordGroups(string text, int limit)
{
var words = text.Split(new string[] { " ", "\r\n", "\n" }, StringSplitOptions.None);
List<string> wordList = new List<string>();
string line = "";
foreach (string word in words)
{
if (!string.IsNullOrWhiteSpace(word))
{
var newLine = string.Join(" ", line, word).Trim();
if (newLine.Length >= limit)
{
wordList.Add(line);
line = word;
}
else
{
line = newLine;
}
}
}
if (line.Length > 0)
wordList.Add(line);
return wordList;
}
答案 4 :(得分:1)
这是一个完整且经过测试的解决方案。
bool overflow
参数指定是否将长字除按空格分割外还进行分块。\r
,\n
被忽略并折叠成一个空格。public static string WrapText(string text, int width, bool overflow)
{
StringBuilder result = new StringBuilder();
int index = 0;
int column = 0;
while (index < text.Length)
{
int spaceIndex = text.IndexOfAny(new[] { ' ', '\t', '\r', '\n' }, index);
if (spaceIndex == -1)
{
break;
}
else if (spaceIndex == index)
{
index++;
}
else
{
AddWord(text.Substring(index, spaceIndex - index));
index = spaceIndex + 1;
}
}
if (index < text.Length) AddWord(text.Substring(index));
void AddWord(string word)
{
if (!overflow && word.Length > width)
{
int wordIndex = 0;
while (wordIndex < word.Length)
{
string subWord = word.Substring(wordIndex, Math.Min(width, word.Length - wordIndex));
AddWord(subWord);
wordIndex += subWord.Length;
}
}
else
{
if (column + word.Length >= width)
{
if (column > 0)
{
result.AppendLine();
column = 0;
}
}
else if (column > 0)
{
result.Append(" ");
column++;
}
result.Append(word);
column += word.Length;
}
}
return result.ToString();
}
答案 5 :(得分:1)
其他答案没有考虑不使用空格来断词的东亚语言。
一般情况下,东亚语言的句子可以在字符之间的任何位置换行,但某些标点符号除外(即使忽略标点符号规则也不是大问题)。它比欧洲语言简单得多,但在考虑混合不同语言时,您必须通过检查 Unicode 表来检测每个字符的语言,然后仅对欧洲语言部分应用空格算法的换行符。
参考资料: https://en.wikipedia.org/wiki/Line_wrap_and_word_wrap https://en.wikipedia.org/wiki/Line_breaking_rules_in_East_Asian_languages
https://en.wikibooks.org/wiki/Unicode/Character_reference/0000-0FFF
答案 6 :(得分:0)
此代码将包装段落文本。它会将段落文本分成几行。如果它遇到任何比行长度更大的单词,它也会将单词分成多行。
private const int max_line_length = 25;
private string wrapLinesToFormattedText(string p_actual_string) {
string formatted_string = "";
int available_length = max_line_length;
string[] word_arr = p_actual_string.Trim().Split(' ');
foreach (string w in word_arr) {
string word = w;
if (word == "") {
continue;
}
int word_length = word.Length;
//if the word is even longer than the length that the line can have
//the large word will get break down into lines following by the successive words
if (word_length >= max_line_length)
{
if (available_length > 0)
{
formatted_string += word.Substring(0, available_length) + "\n";
word = word.Substring(available_length);
}
else
{
formatted_string += "\n";
}
word = word + " ";
available_length = max_line_length;
for (var count = 0;count<word.Length;count++) {
char ch = word.ElementAt(count);
if (available_length==0) {
formatted_string += "\n";
available_length = max_line_length;
}
formatted_string += ch;
available_length--;
}
continue;
}
if ((word_length+1) <= available_length)
{
formatted_string += word+" ";
available_length -= (word_length+1);
continue;
}
else {
available_length = max_line_length;
formatted_string += "\n"+word+" " ;
available_length -= (word_length + 1);
continue;
}
}//end of foreach loop
return formatted_string;
}
//end of function wrapLinesToFormattedText
Blockquote
答案 7 :(得分:0)
这里是经过严格测试并使用LastIndexOf来加快(猜测)速度的对象:
private static string Wrap(string v, int size)
{
v = v.TrimStart();
if (v.Length <= size) return v;
var nextspace = v.LastIndexOf(' ', size);
if (-1 == nextspace) nextspace = Math.Min(v.Length, size);
return v.Substring(0, nextspace) + ((nextspace >= v.Length) ?
"" : "\n" + Wrap(v.Substring(nextspace), size));
}
答案 8 :(得分:0)
这是一小段优化的代码,用于根据Visual Basic9中编写的浮动句子长度限制来包装文本。
Dim stringString = "Great code! I wish I could found that when searching for Print Word Wrap VB.Net and other variations when searching on google. I’d never heard of MeasureString until you guys mentioned it. In my defense, I’m not a UI programmer either, so I don’t feel bad for not knowing"
Dim newstring = ""
Dim t As Integer = 1
Dim f As Integer = 0
Dim z As Integer = 0
Dim p As Integer = stringString.Length
Dim myArray As New ArrayList
Dim endOfText As Boolean = False REM to exit loop after finding the last words
Dim segmentLimit As Integer = 45
For t = z To p Step segmentLimit REM you can adjust this variable to fit your needs
newstring = String.Empty
newstring += Strings.Mid(stringString, 1, 45)
If Strings.Left(newstring, 1) = " " Then REM Chr(13) doesn't work, that's why I have put a physical space
newstring = Strings.Right(newstring, newstring.Length - 1)
End If
If stringString.Length < 45 Then
endOfText = True
newstring = stringString
myArray.Add(newstring) REM fills the last entry then exits
myArray.TrimToSize()
Exit For
Else
stringString = Strings.Right(stringString, stringString.Length - 45)
End If
z += 44 + f
If Not Strings.Right(newstring, 1) = Chr(32) Then REM to detect space
Do Until Strings.Right(newstring, z + 1) = " "
If Strings.Right(newstring, z + f) = " " OrElse Strings.Left(stringString, 1) = " " Then
Exit Do
End If
newstring += Strings.Left(stringString, 1)
stringString = Strings.Right(stringString, stringString.Length - 1) REM crops the original
p = stringString.Length REM string from left by 45 characters and additional characters
t += f
f += 1
Loop
myArray.Add(newstring) REM puts the resulting segments of text in an array
myArray.TrimToSize()
newstring = String.Empty REM empties the string to load the next 45 characters
End If
t = 1
f = 1
Next
For Each item In myArray
MsgBox(item)
'txtSegmentedText.Text &= vbCrLf & item
Next
答案 9 :(得分:0)
我知道我来晚了,但是我设法通过使用递归获得了解决方案。 我认为这是这里提出的最干净的解决方案之一。
递归函数:
migrate
用法:
public StringBuilder TextArea { get; set; } = new StringBuilder();
public void GenerateMultiLineTextArea(string value, int length)
{
// first call - first length values -> append first length values, remove first length values from value, make second call
// second call - second length values -> append second length values, remove first length values from value, make third call
// third call - value length is less then length just append as it is
if (value.Length <= length && value.Length != 0)
{
TextArea.Append($"|{value.PadRight(length)}" + "|");
}
else
{
TextArea.Append($"|{value.Substring(0, length).ToString()}".PadLeft(length) + "|\r\n");
value = value.Substring(length, (value.Length) - (length));
GenerateMultiLineTextArea(value, length);
}
}
输出:
string LongString =
"This is a really long string that needs to break after it reaches a certain limit. " +
"This is a really long string that needs to break after it reaches a certain limit." + "This is a really long string that needs to break after it reaches a certain limit.";
GenerateMultiLineTextArea(LongString, 22);
Console.WriteLine("/----------------------\\");
Console.WriteLine(TextArea.ToString());
Console.WriteLine("\\----------------------/");