自动换行程序C

问题描述 投票:0回答:3

在《C 编程语言》第 1 章的末尾,有一些练习需要完成。我现在正在做的一个程序要求您制作一个程序,将一长串文本以特定长度包装成多行。无论指定的行的最大宽度如何,除了最后一行不被换行之外,以下函数都 100% 有效。 // wrap: take a long input line and wrap it into multiple lines void wrap(char s[], const int wrapline) { int i, k, wraploc, lastwrap; lastwrap = 0; // saves character index after most recent line wrap wraploc = 0; // used to find the location for next word wrap for (i = 0; s[i] != '\0'; ++i, ++wraploc) { if (wraploc >= wrapline) { for (k = i; k > 0; --k) { // make sure word wrap doesn't overflow past maximum length if (k - lastwrap <= wrapline && s[k] == ' ') { s[k] = '\n'; lastwrap = k+1; break; } } wraploc = 0; } } // end main loop for (i = 0; i < wrapline; ++i) printf(" "); printf("|\n"); printf("%s\n", s); }

我发现问题出在变量 
wraploc

上,该变量会递增,直到大于

wrapline
(一行的最大索引)。一旦大于
wrapline
,就会在适当的位置插入换行符,并将
wraploc
重置为 0。

问题在于,在最后一行,

wraploc

永远不会大于

wrapline
,即使它应该是。它在字符串的整个迭代过程中完美递增,直到最后一行。举个例子:

char s[] = "This is a sample string the last line will surely overflow"; wrap(s, 15);


$ ./a.out | this is a sample string the last line will surely overflow
该线代表应该换行的位置。在本例中,当字符数明显多于该值时,
wraploc

的值为 14。


我不知道为什么会发生这种情况,有人可以帮助我吗?

(而且我是 C 语言的初学者,没有任何指针经验,所以请远离您答案中的内容,谢谢)。

c word-wrap
3个回答
4
投票

这是我的回答:

inline int wordlen(const char * str){ int tempindex=0; while(str[tempindex]!=' ' && str[tempindex]!=0 && str[tempindex]!='\n'){ ++tempindex; } return(tempindex); } void wrap(char * s, const int wrapline){ int index=0; int curlinelen = 0; while(s[index] != '\0'){ if(s[index] == '\n'){ curlinelen=0; } else if(s[index] == ' '){ if(curlinelen+wordlen(&s[index+1]) >= wrapline){ s[index] = '\n'; curlinelen = 0; } } curlinelen++; index++; } }


    


3
投票
wraploc

递增

i
,直到达到
wrapline
(示例中为 15)。
当您换行时,您将从 
i
回溯到最后一个空格。
这意味着在下一行中,在 
lastwrap
位置和
i
之间已经有一些字符,即,您无法在那里将
wraploc
重置为 0。
尝试设置 
wraploc = i-lastwrap
    


0
投票

所做的调整:

扩展可断行字符集以包括连字符、制表符等
  • 实现 switch() 以便于轻松扩展该字符集。
    将结果存储在返回给调用者的已分配缓冲区中。
  • 我们不会覆盖易断字符:连字符、制表符等,而是将它们存储在缓冲区中。
    • 将换行符添加到输出缓冲区以信号换行符
    • 禁止不需要的字符进入缓冲区(例如回车符(' ')
    • 翻译制表符并将可变定义的空格字符放入缓冲区。
    丑陋——在不幸的情况下打断一个长单词。 “不幸的情况”定义为:
  • 当不丑陋地破坏一个单词时,会导致占用的空间超过 当前行的用户定义百分比
  • 带有输出的可运行测试代码位于
here

#include <stdio.h> #include <string.h> #include <stdlib.h> #define TRUE 1 #define FALSE 0 #define SPACE (char)('+') /*visible representation of tab replacement for analysis */ void ErrorExit(char *str) { puts(str); exit(0); } /*-------------------------------------------------------------------------- next_break() Algo: function does a look-ahead for a space, a hyphen... anything that constitutes a natural sentence break oppty. Returns the index of the break oppty to the caller. *--------------------------------------------------------------------------*/ int next_break(const char * str) { int done = FALSE, tempindex= -1; char ch; while(!done) { ch = str[++tempindex]; switch( ch ) { case 0: case (char)' ': case (char)'\n': case (char)'\t': case (char)'-': done = TRUE; break; default: break; } } return(tempindex); } /*------------------------------------------------------------------------------------- wordwrap() Algo: parses a long string looking for line break opportunities with every char. If a break oppty is found at cuurent offs, does a qwk scan ahead via next_break() to see if a better oppty exists ahead. ('Better' means closer to the margin but NOT past the margin) If no better oppty found ahead, inserts a newline into buffer & restarts the line count. Else, postpones the newline until chars are read up to the better oppty. Inputs: char *src buffer needing word wrap formatting. int max_line_len for wrap margin. int pointer *ugly_breaks for returning number of middle-of-word breaks. Returns a buffer having the formatted text. *-------------------------------------------------------------------------------------*/ char *wordwrap(const char *src, const int max_line_len, int *ugly_breaks) { int src_idx=0, dest_idx = 0, cur_line_len = 0, done = FALSE; char ch; char *dest = malloc(strlen(src)*3); /* Enough space for even the worst of wrap possibilities.*/ int new_line_needed = FALSE; if(!dest) ErrorExit("Memory Allocation error in wordwrap"); while(!done) { ch = src[src_idx]; switch(ch) { case 0: done = TRUE; break; case (char)' ': case (char)'-': dest[dest_idx++]=ch; /* No matter what happens next, we will include this char... */ cur_line_len++; /* ... and so of course we need to say this. */ /* Would the next break oppty put us past the margin/line limit? */ if(cur_line_len + next_break(&src[src_idx+1]) >= max_line_len) { /* A: Yes. Take the break oppty here, Now*/ new_line_needed = TRUE; } break; case (char)'\n': /* NOTE: you don't have to honor existing line breaks in the text. * You can comment out these next 2 lines (and remove the newline ('\n') case in * function next_break()) to completely reformat paragraphs. It's actually more * aesthetic if you do, but this is an opinion, and so I leave the code here. */ dest[dest_idx++]=ch; cur_line_len=0; break; case (char)'\r': /* Nope, stripping these */ break; case (char)'\t': /* Tab, replace with space(s)*/ if(cur_line_len+1 + next_break(&src[src_idx+1]) >= max_line_len) { /* We have a tab as the last character of the current line. * You can expect this to be rare and it is. But if you don't * care for it, result will be disappointing sooner or later*/ new_line_needed = TRUE; } else { /* Replace the 4s here with any tab stop you like. 8 is the standard.*/ int to_add = 4-((cur_line_len)%4); while(to_add-- && cur_line_len < max_line_len) { dest[dest_idx++]=SPACE; /* Adaptable space replacement char */ cur_line_len++; } } break; default: dest[dest_idx++]=ch; cur_line_len++; break; } /* Has one of our cases flagged a need for newline? */ if(new_line_needed) { int space_remaining = (max_line_len-cur_line_len); double percent_remain = 0.0; new_line_needed = FALSE; /* We now take the newline request as advisement. We inspect * the length of remaining chars on the current line before we agree. * If some long word is next, then we're going to break it up ugly * instead of leaving a lot of unused space in our buffer/application. * It's merely trading one kind of ugly (unused space) for another (broken word). * * We want to keep going (no newline) if more than -- say 10% -- of current line * would become white space by newlining right now. * * Set percent_remain tolerance lower than 10% to get more greedy * with space conservation but get more ugly word breaks. * * 5% (0.05) is pretty nice with an avg of only 2 ugly breaks per * a paragraph with a "reasonable" margin (70 chars or more). * * Set to 100% (1.0) and you won't get any ugly breaks -- unless * you encounter a Huge word that is longer than your margin limit. */ if(cur_line_len > 0 ) percent_remain = (double)space_remaining/cur_line_len; if(percent_remain < 0.10) { /* Not much space remaining, we can newline here */ dest[dest_idx++]='\n'; cur_line_len = 0; } } /* Since we are habitually ignoring new line requests made by the cases, * -- AND because it is possible to get some long character sequence or word * which may exceed our margin -- * ... check for margin overflow with every loop. */ if(cur_line_len >= max_line_len) { /* We have or will overflow with next char. * This is called breaking the word ugly. Sorry babe.*/ dest[dest_idx++]='\n'; cur_line_len = 0; /* Track ugly breaks for tolerance & adjusting newline rejections*/ (*ugly_breaks)++; } src_idx++; } dest[dest_idx++]='\0'; /* cap it */ return dest; }

© www.soinside.com 2019 - 2024. All rights reserved.