C 接受关于传递关系的输入
C take input about transitive relations
如何接受这样的输入:
a<b
b<c
还有这样的:
a<b,c
d<e
f<x,y,z
目前我能够读取像 a < b 这样的单个语句,但不能像 a < b,c 这样读取一行中的多个语句。
我的单个语句代码是:
char a, b;
while(scanf("%c<%c\n", &a, &b) == 2)
/* Set alpha[0..26][0..26] to 1 */
alpha[a - 'a'][b - 'a'] = 1;
我对每行多个语句尝试了类似这样的方法:
char a;
while(scanf("%c<", &a)) {
char b;
while(scanf("%c,", &b)) {
if(getchar() == '\n') break;
/* Set alpha[0..26][0..26] to 1 */
alpha[a - 'a'][b - 'a'] = 1;
}
}
但它不符合我的要求。它卡在第一个 while 循环中。
我不太擅长 scanf 和读取 C 中的输入。所以一些帮助将不胜感激。
你可以用getchar
来解决。
以下 code
可行:
#include <stdio.h>
#include <stdlib.h>
int main(){
int a;
int b;
char alpha[100][100];
while ((a=getchar()) != EOF) {
getchar(); // for <
while((b=getchar()) != '\n') {
/* Set alpha[0..26][0..26] to 1 */
alpha[a - 'a'][b - 'a'] = 1;
b = getchar();
if (b == ',')
continue;
else
break;
}
}
return 0;
}
将每个表达式读入一个字符串,然后使用sscanf()
和%n
模式解析它以获得解析部分的长度。 (请注意,%n
不被大多数 C 库计为转换。)
例如:
#include <stdlib.h>
#include <stdio.h>
#define STRINGIFY_(x) #x
#define STRINGIFY(x) STRINGIFY_(x)
#ifndef MAX_WORD_LEN
#define MAX_WORD_LEN 31
#endif
#define SCAN_WORD "%" STRINGIFY(MAX_WORD_LEN) "[^\t\n\v\f\r <,;]"
const char *parse(const char *spec,
void (*callback)(const char *less, const char *greater))
{
char less[MAX_WORD_LEN+1];
char more[MAX_WORD_LEN+1];
int len;
while (1) {
/* Skip an optional semicolon. */
len = -1;
if (sscanf(spec, " ; %n", &len) >= 0 && len > 0)
spec += len;
/* Try parsing the first pair. */
len = -1;
if (sscanf(spec, " " SCAN_WORD " < " SCAN_WORD " %n", less, more, &len) < 2 || len < 0)
break;
/* Report it. */
if (callback)
callback(less, more);
/* Scan additional right sides. */
spec += len;
while (1) {
len = -1;
if (sscanf(spec, " , " SCAN_WORD " %n", more, &len) < 1 || len < 0)
break; /* Only out of this inner while loop. */
/* Report this one too. */
if (callback)
callback(less, more);
spec += len;
}
}
/* Return a pointer to the first unparsed character. */
return spec;
}
将其应用于命令行中指定的每个表达式的示例程序:
void report(const char *left, const char *right)
{
printf(" %s < %s\n", left, right);
}
int main(int argc, char *argv[])
{
int arg;
const char *end;
for (arg = 1; arg < argc; arg++) {
printf("%s:\n", argv[arg]);
end = parse(argv[arg], report);
if (*end)
printf("but with '%s' not parsed.\n", end);
else
printf("completely parsed.\n");
}
return EXIT_SUCCESS;
}
如果你把上面的编译成example
,而你运行
./example 'foo < bar foo < baz, war war < bar'
程序会输出
foo < bar foo < baz, war war < bar:
foo < bar
foo < baz
foo < war
war < bar
completely parsed.
也就是说,回调函数(report()
,上文)将针对每个唯一对调用一次。它接受 "words" 作为名称,而不仅仅是单个字母。每个 "word" 最多可以包含 31 个字符,并且可以包含除空格、<
、,
或 ;
.
之外的任何字符
为了完整起见,它允许在子表达式之间使用分号,并忽略它们。
逻辑本身很简单。
首先,parse()
尝试扫描分号。它周围的任何空格也将被跳过。
接下来,它会尝试扫描一对 "words",中间有一个 <
。如果失败,它会跳出无限循环,并且 returns 指向第一个未解析字符的指针。如果表达式的语法正确,它将指向 NUL 字节 ([=24=]
)。
如果扫描到一对,则为该对调用回调函数(除非回调函数为 NULL)。
接下来,内部循环尝试扫描逗号后跟 "word"。只要此操作成功,就会为该对调用回调函数(使用原来的左侧,而这个新的 "word" 作为右侧)。否则,我们跳出内循环,并开始新的外循环迭代。
所以,如果我们看foo < bar foo < baz, war war < bar
,那么foo < bar
将被外循环的第一次迭代解析; foo < baz
会被外循环的第二次迭代解析,, war
会被内循环解析;最后 war < bar
将被最外层循环的第三次迭代解析。
如何接受这样的输入:
a<b
b<c
还有这样的:
a<b,c
d<e
f<x,y,z
目前我能够读取像 a < b 这样的单个语句,但不能像 a < b,c 这样读取一行中的多个语句。
我的单个语句代码是:
char a, b;
while(scanf("%c<%c\n", &a, &b) == 2)
/* Set alpha[0..26][0..26] to 1 */
alpha[a - 'a'][b - 'a'] = 1;
我对每行多个语句尝试了类似这样的方法:
char a;
while(scanf("%c<", &a)) {
char b;
while(scanf("%c,", &b)) {
if(getchar() == '\n') break;
/* Set alpha[0..26][0..26] to 1 */
alpha[a - 'a'][b - 'a'] = 1;
}
}
但它不符合我的要求。它卡在第一个 while 循环中。 我不太擅长 scanf 和读取 C 中的输入。所以一些帮助将不胜感激。
你可以用getchar
来解决。
以下 code
可行:
#include <stdio.h>
#include <stdlib.h>
int main(){
int a;
int b;
char alpha[100][100];
while ((a=getchar()) != EOF) {
getchar(); // for <
while((b=getchar()) != '\n') {
/* Set alpha[0..26][0..26] to 1 */
alpha[a - 'a'][b - 'a'] = 1;
b = getchar();
if (b == ',')
continue;
else
break;
}
}
return 0;
}
将每个表达式读入一个字符串,然后使用sscanf()
和%n
模式解析它以获得解析部分的长度。 (请注意,%n
不被大多数 C 库计为转换。)
例如:
#include <stdlib.h>
#include <stdio.h>
#define STRINGIFY_(x) #x
#define STRINGIFY(x) STRINGIFY_(x)
#ifndef MAX_WORD_LEN
#define MAX_WORD_LEN 31
#endif
#define SCAN_WORD "%" STRINGIFY(MAX_WORD_LEN) "[^\t\n\v\f\r <,;]"
const char *parse(const char *spec,
void (*callback)(const char *less, const char *greater))
{
char less[MAX_WORD_LEN+1];
char more[MAX_WORD_LEN+1];
int len;
while (1) {
/* Skip an optional semicolon. */
len = -1;
if (sscanf(spec, " ; %n", &len) >= 0 && len > 0)
spec += len;
/* Try parsing the first pair. */
len = -1;
if (sscanf(spec, " " SCAN_WORD " < " SCAN_WORD " %n", less, more, &len) < 2 || len < 0)
break;
/* Report it. */
if (callback)
callback(less, more);
/* Scan additional right sides. */
spec += len;
while (1) {
len = -1;
if (sscanf(spec, " , " SCAN_WORD " %n", more, &len) < 1 || len < 0)
break; /* Only out of this inner while loop. */
/* Report this one too. */
if (callback)
callback(less, more);
spec += len;
}
}
/* Return a pointer to the first unparsed character. */
return spec;
}
将其应用于命令行中指定的每个表达式的示例程序:
void report(const char *left, const char *right)
{
printf(" %s < %s\n", left, right);
}
int main(int argc, char *argv[])
{
int arg;
const char *end;
for (arg = 1; arg < argc; arg++) {
printf("%s:\n", argv[arg]);
end = parse(argv[arg], report);
if (*end)
printf("but with '%s' not parsed.\n", end);
else
printf("completely parsed.\n");
}
return EXIT_SUCCESS;
}
如果你把上面的编译成example
,而你运行
./example 'foo < bar foo < baz, war war < bar'
程序会输出
foo < bar foo < baz, war war < bar:
foo < bar
foo < baz
foo < war
war < bar
completely parsed.
也就是说,回调函数(report()
,上文)将针对每个唯一对调用一次。它接受 "words" 作为名称,而不仅仅是单个字母。每个 "word" 最多可以包含 31 个字符,并且可以包含除空格、<
、,
或 ;
.
为了完整起见,它允许在子表达式之间使用分号,并忽略它们。
逻辑本身很简单。
首先,parse()
尝试扫描分号。它周围的任何空格也将被跳过。
接下来,它会尝试扫描一对 "words",中间有一个 <
。如果失败,它会跳出无限循环,并且 returns 指向第一个未解析字符的指针。如果表达式的语法正确,它将指向 NUL 字节 ([=24=]
)。
如果扫描到一对,则为该对调用回调函数(除非回调函数为 NULL)。
接下来,内部循环尝试扫描逗号后跟 "word"。只要此操作成功,就会为该对调用回调函数(使用原来的左侧,而这个新的 "word" 作为右侧)。否则,我们跳出内循环,并开始新的外循环迭代。
所以,如果我们看foo < bar foo < baz, war war < bar
,那么foo < bar
将被外循环的第一次迭代解析; foo < baz
会被外循环的第二次迭代解析,, war
会被内循环解析;最后 war < bar
将被最外层循环的第三次迭代解析。