自动换行功能

发布于 2024-07-26 08:05:42 字数 1629 浏览 4 评论 0原文

大家好,我正在用 C++ 编写一个自动换行函数来格式化控制台文本。 我的问题是 A) 我不完全理解 std::string::iterators 的作用,或者 B) 我的迭代器之一没有正确设置。 任何人都可以阐明此代码失败的原因吗?

顺便说一句:抱歉,如果这涉及到太多细节。 我不确定大多数程序员(我是“新手”)是否在他们的机器上安装了 C++ 编译器。

std::string wordWrap(std::string sentence, int width)
{    
   //this iterator is used to optimize code; could use array indice 
   //iterates through sentence till end 
   std::string::iterator it = sentence.begin();
   //this iterator = it when you reach a space; will place a newline here
   //if you reach width;
   std::string::iterator lastSpace = sentence.begin();

   int distanceToWidth = 0;

   while (it != sentence.end())
   {
      while (it != sentence.end() && distanceToWidth < width)
      {
         if (*it == ' ')
         {
           lastSpace = it;
         }

         distanceToWidth++;
         it++;
     }

     distanceToLength = 0;
     *lastSpace = '\n';   

      //skip the space
      if (it != sentence.end())
      {
         it++;
      }
   }

   return sentence;    
}

我没有得到正确的输出。 假设我这样称呼它:

std::cout << wordWrap("a b c abcde abcdef longword shtwd", 5) << std::endl << std::endl;
std::cout << wordWrap("this is a sentence of massive proportions", 4) << std::endl;

我得到的输出不令人满意:

a b 
c
abcde
abcdef
longword
shtwd

//yes I get his, instead of this
his is
a
sentence
of
massive
proportions
Press any key to continue . . .

我的问题是,我在不适当的时候得到换行符。 我经常收到换行符,而且我没有看到任何明显的错误来解释为什么会这样。 我希望独立的人(我在这个算法上花了几个小时,没有得到正确的结果是相当令人沮丧的)可以看看它。 另外,有什么明显的优化技巧吗?

Hey guys, I'm writing a word wrap function to format console text in C++. My problem is either A) I don't understand exactly what std::string::iterators do, or B) one of my iterators is not being set properly. Can anyone shed some light on the reason this code fails?

by the way: sorry if this goes into too much detail. I'm not sure if most programmers (I'm a "newbie") have a C++ compiler installed on their machine.

std::string wordWrap(std::string sentence, int width)
{    
   //this iterator is used to optimize code; could use array indice 
   //iterates through sentence till end 
   std::string::iterator it = sentence.begin();
   //this iterator = it when you reach a space; will place a newline here
   //if you reach width;
   std::string::iterator lastSpace = sentence.begin();

   int distanceToWidth = 0;

   while (it != sentence.end())
   {
      while (it != sentence.end() && distanceToWidth < width)
      {
         if (*it == ' ')
         {
           lastSpace = it;
         }

         distanceToWidth++;
         it++;
     }

     distanceToLength = 0;
     *lastSpace = '\n';   

      //skip the space
      if (it != sentence.end())
      {
         it++;
      }
   }

   return sentence;    
}

I'm not getting correct output. Assuming I called it like this:

std::cout << wordWrap("a b c abcde abcdef longword shtwd", 5) << std::endl << std::endl;
std::cout << wordWrap("this is a sentence of massive proportions", 4) << std::endl;

I get unsatisfying output of this:

a b 
c
abcde
abcdef
longword
shtwd

//yes I get his, instead of this
his is
a
sentence
of
massive
proportions
Press any key to continue . . .

My problem is that I'm am getting newlines when inappropiate. I am getting newlines too often, and I don't see any obvious error as to why that is. I was hoping someone independent (I've spent a few hours on this algorithm, and to not have the right results is quite frusturating) of the problem could look at it. Also, any obvious optimization tips?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

遥远的绿洲 2024-08-02 08:05:43

问题是单词 this 有 4 个字符,而您要换行为 4 个字符。 所以它试图在将lastSpace 设置为合理的值之前进行换行。

从单步执行代码的角度来看:

lastSpace points to the "t" from the beginning of "this"
distanceToWidth=0
iterator=this is
         ^

check if we should loop (distanceToWidth<4)
is the current character a space? no
distanceToWidth=1
iterator=this is
          ^

check if we should loop (distanceToWidth<4)
is the current character a space? no
distanceToWidth=2
iterator=this is
           ^

check if we should loop (distanceToWidth<4)
is the current character a space? no
distanceToWidth=3;
iterator=this is
            ^

check if we should loop (distanceToWidth<4)
is the current character a space? no
distanceToWidth=4;
iterator=this is
             ^

check if we should loop (distanceToWidth<4) NO! Because distanceToWidth equals four!

We break out of the loop.

Recall that lastSpace was never modified it still points to the first character in the string!
now we set the "t" character from "this" to be a newline!!

ETC

因此,我们输出一个额外的换行符,而不是“this”中的“t”

来修复它......好吧......你可以弄清楚

The problem is that the word this is 4 characters, and you are wrapping at four characters. So it is trying to wrap before it has set lastSpace to something reasonable.

Look at it from the point of stepping through the code:

lastSpace points to the "t" from the beginning of "this"
distanceToWidth=0
iterator=this is
         ^

check if we should loop (distanceToWidth<4)
is the current character a space? no
distanceToWidth=1
iterator=this is
          ^

check if we should loop (distanceToWidth<4)
is the current character a space? no
distanceToWidth=2
iterator=this is
           ^

check if we should loop (distanceToWidth<4)
is the current character a space? no
distanceToWidth=3;
iterator=this is
            ^

check if we should loop (distanceToWidth<4)
is the current character a space? no
distanceToWidth=4;
iterator=this is
             ^

check if we should loop (distanceToWidth<4) NO! Because distanceToWidth equals four!

We break out of the loop.

Recall that lastSpace was never modified it still points to the first character in the string!
now we set the "t" character from "this" to be a newline!!

ETC

Thus we output an extra newline instead of the "t" in "this"

about fixing it... well... you can figure it out

小巷里的女流氓 2024-08-02 08:05:43

lastSpace 迭代器从 sentence 的第一个字符开始:

//this iterator = it when you reach a space; will place a newline here
//if you reach width;
std::string::iterator lastSpace = sentence.begin();

当到达“this is a...”的第五个字符(空格)时,内部 while 循环退出(因为distanceToWidth == width),在识别出当前字符是空格之前。 然后在 lastSpace 位置插入换行符,该位置仍然指向字符串的第一个字符。 这样“this”的“t”就丢失了。

接下来 distanceToWidth 重置为零,并附加另一个 width 字符,尽管该行没有在当前位置分割,但之前的一些字符(在 lastSpace代码>)。 因此这一行最终可能包含比预期更多的字符。 在示例中,“is”仍然与“this”在同一行,但应换行到下一行。

您可能需要:

  • 将内部 while 的条件更改为 <= 以便检查正确的宽度,
  • 而不是将 lastSpace 初始化为字符串的第一个字符。 可能更好:

std::string::iterator lastSpace;
...
if (lastSpace) {
   *lastSpace = '\n';
}
  • 计算自最后一个空格以来找到的字符数,并在插入换行符后使用它来重置 distanceToWidth

The lastSpace iterator starts on the first character of sentence:

//this iterator = it when you reach a space; will place a newline here
//if you reach width;
std::string::iterator lastSpace = sentence.begin();

When you reach the fifth character of "this is a..." (the space), the inner while loop exits (because distanceToWidth == width), before it is recognized that the current character is a space. Then a newline is inserted in position lastSpace, which still points to the first character of the string. This way the "t" of "this" is lost.

Next distanceToWidth is reset to zero and another width characters are appended, although the line was not split at the current position, but some characters before (at lastSpace). So this line can end up containing more characters than expected. In the example, "is" is still on the same line as "this" while it should be wrapped to the next line.

You probably need to:

  • change the condition of the inner while to <= so that the correct width is checked
  • not initialize lastSpace to the first character of the string. Probably better:

std::string::iterator lastSpace;
...
if (lastSpace) {
   *lastSpace = '\n';
}
  • count how many characters were found since the last space, and uses this to reset distanceToWidth after inserting a line break
反话 2024-08-02 08:05:43

从代码显示的内容来看,您的输出是正确的。 你错的是算法。 使用调试器来找出实际发生的情况。

Your output is correct from what your code shows. What you got wrong is the algorithm. Use a debugger to find out what actually happens.

帅气尐潴 2024-08-02 08:05:43

更新:这是我的最新代码,显示正确的输出。 如果您再次阅读本文,请发表评论。 很抱歉格式错误,但在每行前面添加四个空格很麻烦,而且现在是凌晨 1:45。

std::string wordWrap(std::string sentence, int width)
{    
//this iterator is used to optimize code; could use array indice 
//iterates through sentence till end 
std::string::iterator it = sentence.begin();
//this iterator = it when you reach a space; will place a newline here
//if you reach width; also kind of hackish (used instead of comparing to NULL)
std::string::iterator lastSpace = sentence.begin();

int distanceToWidth = 0;

//used in rare instance that there is a space
//at the end of a line
bool endOfLine = false;

while (it != sentence.end())
{
   //TODO: possible to stop recomparing against .end()?
   while (it != sentence.end() && distanceToWidth <= width)
   {
      distanceToWidth++;

      if (*it == ' ')
      {
         lastSpace = it;

         //happens if there is a space after the last character
         if (width == distanceToWidth)
         {
            *lastSpace = '\n'; 
         }
      }

      ++it;
   }

   //happens when lastSpace did encounter a space
  //otherwise
   if (lastSpace != sentence.begin())
   {
      *lastSpace = '\n';   
   }       

   lastSpace = sentence.begin();
   distanceToWidth = 0;
   }

   return sentence;    
}

Update: here is my latest code, showing correct output. Please comment if you read this again. Sorry for bad formatting, but it's a hassle to add four spaces in front of each line and it is 1:45 AM.

std::string wordWrap(std::string sentence, int width)
{    
//this iterator is used to optimize code; could use array indice 
//iterates through sentence till end 
std::string::iterator it = sentence.begin();
//this iterator = it when you reach a space; will place a newline here
//if you reach width; also kind of hackish (used instead of comparing to NULL)
std::string::iterator lastSpace = sentence.begin();

int distanceToWidth = 0;

//used in rare instance that there is a space
//at the end of a line
bool endOfLine = false;

while (it != sentence.end())
{
   //TODO: possible to stop recomparing against .end()?
   while (it != sentence.end() && distanceToWidth <= width)
   {
      distanceToWidth++;

      if (*it == ' ')
      {
         lastSpace = it;

         //happens if there is a space after the last character
         if (width == distanceToWidth)
         {
            *lastSpace = '\n'; 
         }
      }

      ++it;
   }

   //happens when lastSpace did encounter a space
  //otherwise
   if (lastSpace != sentence.begin())
   {
      *lastSpace = '\n';   
   }       

   lastSpace = sentence.begin();
   distanceToWidth = 0;
   }

   return sentence;    
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文