依赖于下一个输入字符的程序?
Program that depends on the next input character?
假设我有一个来自 stdin
:
的输入字符串
(5(4(11(7()())(2()()))()) (8(13()())(4()(1()()))))
鉴于我读过一个字符(
,可能有两种可能性:
- 一个整数
int d
。 (注意 d
可能包含多个字符。例如上面的 13
)
- 右括号
)
我需要根据每个案例做不同的任务:
- 如果它是整数,那么我需要将它读入
d
。
- 如果是
)
那么我会做一些计算然后丢弃它。
此外,输入中的任何可见字符之间可能有任意数量的空格或换行符,所以我怎么知道下一个可见字符是整数还是 )
?
您可以使用 scanf
。它告诉您是否可以进行转换。如果不是,下一次扫描将重新扫描相同的输入。所以:
for (;;) {
int d;
int res = scanf("%d", &d); // try a number
if (res == EOF) break; // end of input
if (res == 1) { // yup, it's a number
printf("int %d\n", d);
} else { // nope, it's a char
char c;
scanf(" %c", &c);
printf("char '%c'\n", c);
}
}
由于您似乎解析了这个字符串并触发了对找到的各种标记的一些操作,一个简单的手工词汇扫描器可以简化。
%n
格式非常方便,一旦检测到整数就可以跳过。
注意:要从 stdin
获取输入字符串,只需使用 fgets()
。
如果它位于多行(如编辑中添加的那样),只需为每个新输入行重复 main()
中的循环。
/**
gcc -std=c99 -o prog_c prog_c.c \
-pedantic -Wall -Wextra -Wconversion \
-Wc++-compat -Wwrite-strings -Wold-style-definition -Wvla \
-g -O0 -UNDEBUG -fsanitize=address,undefined
**/
#include <stdio.h>
#include <ctype.h>
#include <stdbool.h>
typedef enum {TK_ERROR, TK_OPEN, TK_CLOSE, TK_INT, TK_END} Token;
Token
scan(const char **input,
int *value)
{
const char *p=*input;
for(char c=*p; c!='[=10=]'; c=*(++p))
{
if(isspace(c))
{
continue; // nothing more to be done
}
if(c=='(')
{
*input=p+1;
return TK_OPEN;
}
if(c==')')
{
*input=p+1;
return TK_CLOSE;
}
int pos=-1;
sscanf(p, "%d%n", value, &pos);
if(pos!=-1)
{
*input=p+pos;
return TK_INT;
}
return TK_ERROR;
}
return TK_END;
}
int
main(void)
{
const char *input="(5(4(11(7()())(2()()))()) (8(13()())(4()(1()()))))";
const char *current=input;
int depth=0;
for(bool stop=false; !stop;)
{
int value=-1;
switch(scan(¤t, &value))
{
case TK_ERROR:
{
printf("unexpected char <%c>\n", *current);
++current; // skip this char
break;
}
case TK_OPEN:
{
++depth;
printf("OPEN depth=%d\n", depth);
break;
}
case TK_CLOSE:
{
printf("CLOSE depth=%d\n", depth);
--depth;
break;
}
case TK_INT:
{
printf("INT %d depth=%d\n", value, depth);
break;
}
case TK_END:
{
stop=true;
break;
}
}
}
return 0;
}
假设我有一个来自 stdin
:
(5(4(11(7()())(2()()))()) (8(13()())(4()(1()()))))
鉴于我读过一个字符(
,可能有两种可能性:
- 一个整数
int d
。 (注意d
可能包含多个字符。例如上面的13
) - 右括号
)
我需要根据每个案例做不同的任务:
- 如果它是整数,那么我需要将它读入
d
。 - 如果是
)
那么我会做一些计算然后丢弃它。
此外,输入中的任何可见字符之间可能有任意数量的空格或换行符,所以我怎么知道下一个可见字符是整数还是 )
?
您可以使用 scanf
。它告诉您是否可以进行转换。如果不是,下一次扫描将重新扫描相同的输入。所以:
for (;;) {
int d;
int res = scanf("%d", &d); // try a number
if (res == EOF) break; // end of input
if (res == 1) { // yup, it's a number
printf("int %d\n", d);
} else { // nope, it's a char
char c;
scanf(" %c", &c);
printf("char '%c'\n", c);
}
}
由于您似乎解析了这个字符串并触发了对找到的各种标记的一些操作,一个简单的手工词汇扫描器可以简化。
%n
格式非常方便,一旦检测到整数就可以跳过。
注意:要从 stdin
获取输入字符串,只需使用 fgets()
。
如果它位于多行(如编辑中添加的那样),只需为每个新输入行重复 main()
中的循环。
/**
gcc -std=c99 -o prog_c prog_c.c \
-pedantic -Wall -Wextra -Wconversion \
-Wc++-compat -Wwrite-strings -Wold-style-definition -Wvla \
-g -O0 -UNDEBUG -fsanitize=address,undefined
**/
#include <stdio.h>
#include <ctype.h>
#include <stdbool.h>
typedef enum {TK_ERROR, TK_OPEN, TK_CLOSE, TK_INT, TK_END} Token;
Token
scan(const char **input,
int *value)
{
const char *p=*input;
for(char c=*p; c!='[=10=]'; c=*(++p))
{
if(isspace(c))
{
continue; // nothing more to be done
}
if(c=='(')
{
*input=p+1;
return TK_OPEN;
}
if(c==')')
{
*input=p+1;
return TK_CLOSE;
}
int pos=-1;
sscanf(p, "%d%n", value, &pos);
if(pos!=-1)
{
*input=p+pos;
return TK_INT;
}
return TK_ERROR;
}
return TK_END;
}
int
main(void)
{
const char *input="(5(4(11(7()())(2()()))()) (8(13()())(4()(1()()))))";
const char *current=input;
int depth=0;
for(bool stop=false; !stop;)
{
int value=-1;
switch(scan(¤t, &value))
{
case TK_ERROR:
{
printf("unexpected char <%c>\n", *current);
++current; // skip this char
break;
}
case TK_OPEN:
{
++depth;
printf("OPEN depth=%d\n", depth);
break;
}
case TK_CLOSE:
{
printf("CLOSE depth=%d\n", depth);
--depth;
break;
}
case TK_INT:
{
printf("INT %d depth=%d\n", value, depth);
break;
}
case TK_END:
{
stop=true;
break;
}
}
}
return 0;
}