试图创建一个文本解析器,在需要的地方插入换行符,但它不是很有效

时间:2012-06-27 05:39:47

标签: c# text-parsing

我正在制作游戏,我从XML文件中读取对话文本。我正在尝试根据需要自动添加换行符,以便它适合文本框。但它不会正常工作。这是目前的代码:

SpriteFont dialogueFont = font31Adelon;
int lastSpace = 0;
string builder = "";
string newestLine = "";
float maxWidth = 921.6f;
float stringLength = 0;

for (int i = 0; i <= speech.Length - 1; i++) //each char in the string
{
    if (speech[i] == ' ') //record the index of the most recent space
    {
        lastSpace = i;
    }

    builder += speech[i]; 
    newestLine += speech[i]; 
    stringLength = dialogueFont.MeasureString(newestLine).X;

    if (stringLength > maxWidth) //longer than allowed
    {
        builder = builder.Remove(lastSpace); //cut off from last space 
        builder += Environment.NewLine;
        i = lastSpace; //start back from the cutoff
        newestLine = "";
    }
}
speech = builder;

我的测试字符串是“这是一个长语音的例子,必须正确分解成多行。它有几行,并没有真正说出重要的东西,因为它只是示例文本。”

这就是演讲结束的方式: http://www.iaza.com/work/120627C/iaza11394935036400.png

第一行有效,因为它恰好是一个超出极限的空间,我认为。

i = 81,lastSpace = 80是第二行结束的地方。构建器在.Remove命令之前看起来像这样: “这是一个很长的演讲的例子,它不会被分成多行c”

运行后它看起来像这样: “这是一个很长的演讲的例子,它不会被分解成多行”

第三行超过了i = 123和lastSpace = 120的大小限制。在.Remove之前看起来像这样: “这是一个很长的演讲的例子,\ r \ n \ n \ n \ n \ n \ n \ n \ n \ n \ n \ n \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \

之后: “这是一个很长的演讲的例子,\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \

正如你所看到的,它会切断一个额外的角色,即使角色80,那个空间,它应该开始移除。从我读过的内容中删除。当使用单个参数调用时,删除包括和在给定索引之后的所有内容。虽然它也削减了i = 79!似乎应该很容易在lastSpace中添加或减去以弥补这一点,但我要么得到“索引越界”错误,要么我切断了更多的字符。我已经尝试过.Remove(lastSpace,i-lastSpace),但这也不起作用。通过在lastSpace中添加或减去,我尝试以不同于其他方式处理“以空格结尾”的情况。我试过以不同的方式解决问题,而且没有一个有效。

我已经厌倦了看这个,任何帮助都会受到赞赏。

3 个答案:

答案 0 :(得分:1)

作为替代方法,您可以使用.split将句子分解为数组,然后填充您的框,直到下一个工作没有空间,然后添加换行符并从下一行开始。

答案 1 :(得分:1)

您将Environment.NewLine添加到StringBuilder,当您指定索引从哪里开始删除时,需要考虑这一点。

Environment.NewLine的值取决于系统。它可以是"\r\n""\n""\r"(或前两个according to MSDN中只有一个)。
在你的情况下它是"\r\n",这意味着删除一个空格,你添加了两个其他字符。

首先,您需要声明一个新变量:

int additionalChars = 0;

然后,在添加一行文本时,您应该将代码更改为以下内容:

builder = builder.Remove(lastSpace + additionalChars); //cut off from last space 
builder += Environment.NewLine;
additionalChars += Environment.NewLine.Length - 1; 

-1是因为您已经删除了一个空格(应该使此代码独立于系统的Environment.NewLine定义。)

更新:您还应该考虑超过行数​​限制的字词。无论如何你应该打破它们(忍不住试试):

if (stringLength > maxWidth) //longer than allowed
{
    // Cut off only if there was a space to cut off at
    if (lastSpace >= 0) { 
        builder = builder.Remove(lastSpace + additionalChars); //cut off from last space 
        i = lastSpace; //start back from the cutoff
    }
    builder += Environment.NewLine;
    // If there was no space that we cut off, there is also no need to subtract it here
    additionalChars += Environment.NewLine.Length - (lastSpace >= 0 ? 1 : 0);
    lastSpace = -1; // Means: No space found yet
    newestLine = "";
}

答案 2 :(得分:0)

你可以做类似下面的代码吗?优点是双重的。首先,它跳到下一个空间来测量并决定是否添加整个单词,而不是逐字逐句。其次,它只对字符串中的每个单词调用一次MeasureString,而不是为每个添加到字符串的字母调用。当单词适合时,它使用带有Append的StringBuilder,或者当它不适合时使用AppendLine并且需要添加新行。

        int lastSpace = 0;
        int nextSpace = s.IndexOf(' ', lastSpace + 1);
        float width = 0;
        float totalWidth = 0;
        float maxWidth = 200;
        while (nextSpace >= 0)
        {
            string piece = s.Substring(lastSpace, nextSpace - lastSpace);
            width = g.MeasureString(piece, this.Font).Width;
            if (totalWidth + width < maxWidth)
            {
                sb.Append(piece);
                totalWidth += width;
            }
            else
            {
                sb.AppendLine(piece);
                totalWidth = 0;
            }
            lastSpace = nextSpace;
            nextSpace = s.IndexOf(' ', lastSpace + 1);
        }
        MessageBox.Show(sb.ToString());