“不可能”的K& R练习。
“编写替换的程序entab 最小的空白串 要实现的选项卡和空白的数量 相同的间距。使用相同的选项卡 停止,说每n列。应该n 是变量还是象征性的 参数?“
我遇到的问题是,我不确定如何正确地做到这一点。我知道这不是很解释,但这就是问题所在。我见过的大多数例子都计算了一些空白,用一个标签取代了那些系列,但这不是它的要求,我想我明白它的要求,但目前感觉不能这样做。
任何人都可以提供帮助:)
编辑:到目前为止我编写的代码can be found here。
答案 0 :(得分:15)
如果您的问题是“这要我做什么?”我想我可以通过解释原始问题来帮助(以不同的方式提出同样的问题)。
编写一个程序,将带有空格的输入文本作为输出,并尽可能使用制表符作为输出在视觉上等效的文本。
例如,每隔8个字符使用tabstops,并将空格显示为“。”和标签为' - ';
input;
".foo:...bar;......#comment"
output;
".foo:-bar;-..#comment"
input;
".......-foo:.....bar;......#comment"
output;
"-foo:-.bar;-...#comment"
编写程序,以便tabstop参数n可以改变,即允许n以外的n值。准备好证明你决定使n成为常数,或者变量。
编辑我查看了您的代码,我认为它比它需要的更复杂。我的建议是一次做一个角色。没有必要缓冲整行。在读取每个字符时保持列数('\ n'将其重置为零,'\ t'将其重置为1或更多,其他字符将其增加)。当你看到一个空格(或标签)时,不要立即发出任何东西,开始你的诱捕过程,发出零个或多个标签,然后再空格(在'\ n'或非空格字符,以先到者为准)。 / p>
最后的提示是状态机可以使这种算法更容易编写,验证,测试和阅读。
编辑2 在无耻地尝试让OP接受我的答案时,我现在已经开始实际编写了一个解决方案,基于我上面提供的提示以及我在讨论中的评论
// K&R Exercise 1-21, entab program, for Stackoverflow.com
#include <stdio.h>
#define N 4 // Tabstop value. Todo, make this a variable, allow
// user to modify it using command line
int main()
{
int col=0, base_col=0, entab=0;
// Loop replacing spaces with tabs to the maximum extent
int c=getchar();
while( c != EOF )
{
// Normal state
if( !entab )
{
// If whitespace goto entab state
if( c==' ' || c=='\t' )
{
entab = 1;
base_col = col;
}
// Else emit character
else
putchar(c);
}
// Entab state
else
{
// Trim trailing whitespace
if( c == '\n' )
{
entab = 0;
putchar( '\n' );
}
// If not whitespace, exit entab state
else if( c!=' ' && c!='\t' )
{
entab = 0;
// Emit tabs to get close to current column position
// eg base_col=1, N=4, col=10
// base_col + 3 = 4 (1st time thru loop)
// base_col + 4 = 8 (2nd time thru loop)
while( (base_col + (N-base_col%N)) <= col )
{
base_col += (N-base_col%N);
putchar( '\t' );
}
// Emit spaces to close onto current column position
// eg base_col=1, N=4, col=10
// base_col -> 8, and two tabs emitted above
// base_col + 1 = 9 (1st time thru this loop)
// base_col + 1 = 10 (2nd time thru this loop)
while( (base_col + 1) <= col )
{
base_col++;
putchar( ' ' );
}
// Emit buffered character after tabs and spaces
putchar( c );
}
}
// Update current column position for either state
if( c == '\t' )
col += (N - col%N); // eg col=1, N=4, col+=3
else if( c == '\n' )
col=0;
else
col++;
// End loop
c = getchar();
}
return 0;
}
答案 1 :(得分:1)
我同意你的评估。用标签替换每个n个空白是不够的;例如,如果n == 4,“hi blank blank blank blank”不应该被“hi tab”替换,而应该被“hi tab blank blank”替换。
听起来您需要做的是在每行读取时跟踪当前位置,并使用此信息确定您需要多少个标签。这有帮助吗?如果您需要更多详细信息,请与我们联系!
对于“变量与符号参数”部分,要么肯定是可行的,但我可以想到使用变量的一个显着优点:您可以在不重新编译的情况下为不同的n值运行程序。
答案 2 :(得分:1)
我有点晚了,但这是我自己解决的问题。它与上面分享的方法不同,所以如果您有任何意见/反馈,请分享。
查看bheklilr's answer以获取源代码。有关于代码的注释,并且该方法在文件的顶部进行了解释,但我会将其复制并粘贴到此处,以便从一开始就清楚逻辑。
方法:
我们会跟踪遇到的空格数量(非空格/非空格字符之间)
我们会跟踪每个输入行的字符(不是标签/空白/换行符)
我们将评估&#34;差距&#34;由空间生成:
评估这些字符之间的空格数。
- 时
差距足够大&#34;当空格数为> = TABSIZE
然后,对于我们&#34;缓冲区&#34;中的所有剩余空格,我们将单独打印出来
最后,我们打印出读入的字符(不是标签/空白)
如果需要,还可以更新空间计数和字符数。
我仍然是一个新手程序员,所以我不确定它与这里发布的其他解决方案的比较,但逻辑似乎更容易理解(至少对我而言)。
希望以后可以帮助别人!
答案 3 :(得分:0)
我的理解是,你不必知道问题是什么或如何解决它来回答这个问题。问题似乎在于询问您是否了解何时使用变量而不是“符号参数”。我真的不确定“符号参数”是什么意思;它似乎是过时的命名法。
话虽如此,解决问题的第一部分(用制表符替换空格)是相当直接的。想想分裂和剩余。
答案 4 :(得分:0)
我粗略地看了一下你的代码,没有任何东西像我公然的错误一样跳出来。
所以我的建议是在调试器中单步执行几个输入示例,随时检查变量值,或者添加一大堆调试打印语句。在任何一种情况下,您的目标都是找到程序状态开始偏离预期或预期的点。
答案 5 :(得分:0)
我目前正在耕作KnR并遇到了这个页面:
您的锻炼位于:
解决方案
第1章 - 教程简介
Ex No 21 Pg No 34
希望您觉得这很有用。
此致 Morpfh
1:http://users.powernet.co.uk/eton/kandr2/index.html“C编程语言”,第2版,Kernighan和Ritchie - 练习答案
答案 6 :(得分:0)
在上面评分最高的答案中,该程序过于复杂。 为了简化答案的这一部分,我附上了一个更简单的代码,希望用K&amp; R的风格编写(主要是用++内联递增)。
int main(){
char newsentence[255],c;
int spacecount = 0, oldsentencepointer = 0, newsentencepointer = 0;
printf("Give me a sentence please:\n");
while ((c = getchar()) != '\n') {
if ((oldsentencepointer != 0) && (oldsentencepointer % TAB == 0) && (spacecount > 0))
{
newsentencepointer -= spacecount; //if at tabstop, and spaces and not
first, go back to 1st space, set tab.
newsentence[newsentencepointer++] = '\t';
spacecount = 0;
}
if (c == ' ') {
newsentence[newsentencepointer++] = ' ';
spacecount++; //keep track of spaces before tab stop
}
else if (c == '\t') {
newsentence[newsentencepointer++] = '\t' ;
oldsentencepointer = TAB; //set old pointer to TAB (does not matter if actual,
only cadence important)
continue; //continue from here so as not to increment
old sentence counter.
}
else {
newsentence[newsentencepointer++] = c ; //write whatever was old into new.
spacecount = 0; //reset space counter.
}
oldsentencepointer++;
}
newsentence[newsentencepointer] = '\0'; //cap it off.
puts(newsentence);
return 0;
}
答案 7 :(得分:0)
有一个更简洁的解决方案,虽然它没有采用可用的最佳代码实践(滥用短路评估,通过继续进行笨拙的控制流程,有点奇怪&#34;空间&#34;循环)。
#include <stdio.h>
#define TS 8
int main(int arg, char *argv[]) {
int counter = 0, space_counter = 0, c;
while ((c = getchar()) != EOF) {
++counter;
if (c == ' ' && ++space_counter && (counter % TS) == 0) {
space_counter = 0;
c = '\t';
} else if (c == '\t') {
counter = space_counter = 0;
} else if (c != ' ') {
while (space_counter--)
putchar(' ');
space_counter = 0;
if (c == '\n')
counter = 0;
} else {
continue; /* don't call putchar(c) */
}
putchar(c);
}
return 0;
}
除了空白之外,每个读取的字符都是逐字打印的。空白被计算在内。如果程序遇到非空白字符,则会打印与之前计数的空白一样多的空白,之后重置该计数器。如果它遇到空白,它将通过第二个计数器(自行/最后一个tabstop开始以来打印的字符)进行检查(如果光标位于tabstop上)。如果是,则打印标签,否则只计算空白。
输入中的选项卡处理重置空间计数器并输出选项卡,从而消除过程中任何多余的空白。