我有一个"a b.c d.e"
形式的输入(引号排除)我想要解析为a1=a, a2=b, a3=c
,...等整数值。但技巧是"."
之后的价值也可能丢失,因此"a b d.e"
,"a b c"
,"a b.c d"
是有效输入。但是"a b. d.e"
无效,因为"b"
之后有一个"."
,但后面没有数字。假设数字即。 "a", "b"
等是大于0且小于1000的整数。
我只能想到这样做的艰难方法。试过这个 - >
scanf("%d %2d[^. ].%2d[^. ] %2d[^. ].%2d[^\n]",&a,&b,&c,&d,&e);
但它不起作用。感谢您使用scanf()
参数技巧解析它。
答案 0 :(得分:1)
如果我理解您对我的评论的回答,那么在这种情况下,我不认为您可以将输入转换为scanf
格式字符串并处理您的变体想要处理。在这种情况下,你可以回到try和true,解析任何东西,在strtol
的帮助下沿着字符串向下走。
strtol
提供结束指针,在输入字符串中有效转换为long
后设置为下一个字符。因此,如果您正在按照复杂的输入字符串进行操作,则从strtol (p, &ep, 10)
开始,其中p
是指向字符串的指针,ep
将设置为下一个字符。第一个转换后的字符串。 (在您的情况下为'.'
或' '
)。如果下一个字符是'.'
,您可以对随后的字符进行进一步的测试,并在逐个收集值时确定输入字符串是否有效。
在您测试所需条件并提前ep
指向要转换的下一个有效数字的开头之后,您只需设置p = ep;
并重复,直到您填写a, b & c
或点击错误的情况。
使用strtol
时,除了检查errno
之外,您还可以使用其他一些验证,但这对于此示例就足够了。有关其余验证,请参阅man strtol
。
如果我正确理解了你的逻辑,你可以做类似以下的事情:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#define MAXC 32
int main (void) {
char buf[MAXC] = "", *p = buf, *ep = NULL;
int a = 0, b = 0, c = 0, tmp = 0;
printf ("enter values: ");
if (!fgets (buf, MAXC, stdin))
return 1;
for (;;) {
tmp = strtol (p, &ep, 10);
if (errno) { /* minimal conversion validation */
fprintf (stderr, "error: failed conversion.\n");
return 1;
}
if (!a) /* handle a */
a = tmp;
else if (!b) { /* handle b */
if (*ep && *ep == '.' && *(ep + 1) && *(ep + 1) == ' ') {
fprintf (stderr, "error: invalid input = '.' alone.\n");
return 1;
}
b = tmp;
if (*ep && *ep == '.' && *(ep + 1) &&
'0' <= *(ep + 1) && *(ep + 1) <= '9')
ep++;
else
while (*ep && (*ep < '0' || '9' < *ep))
ep++;
if (!*ep) {
fprintf (stderr, "error: invalid input - no 'c'.\n");
return 1;
}
}
else if (!c) { /* handle c */
if (*ep && *ep == '.' && *(ep + 1) &&
(*(ep + 1) == ' ' || *(ep + 1) == '\n')) {
fprintf (stderr, "error: invalid input = '.' alone.\n");
return 1;
}
c = tmp;
break;
}
p = ep;
}
printf ("a : %d\nb : %d\nc : %d\n", a, b, c);
return 0;
}
示例使用/输出
$ ./bin/triplet
enter values: 1 2.3 4.5
a : 1
b : 2
c : 3
$ ./bin/triplet
enter values: 1 2 3.4
a : 1
b : 2
c : 3
$ ./bin/triplet
enter values: 1 2 3
a : 1
b : 2
c : 3
$ ./bin/triplet
enter values: 1 2.3 4
a : 1
b : 2
c : 3
$ ./bin/triplet
enter values: 1 2. 3.4
error: invalid input = '.' alone.
仔细看看,让我知道我是否误解了你的评论。如果没有,请记住你可以通过简单地沿着字符串走一个指针(或一对指针)来解析任何东西。
答案 1 :(得分:1)
没有简单的方法可以将scanf()
用于您的目的。如果您想要严格验证输入,则必须编写一个定制的解析器。
这是一个解决方案:
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
char *skipblanks(char *p) {
while (isblank((unsigned char)*p)
p++;
return p;
}
int getnumber(char *p, char **pp, int *dest) {
if (strchr("0123456789+-", *p) {
long val;
errno = 0;
val = strtol(p, pp, 10);
if (errno == 0 && *pp > p && val >= INT_MIN && val <= INT_MAX) {
*dest = val;
return 1;
}
}
return 0;
}
int parseinput(char *p, int *a, int *b, int *c, int *d, int *e)) {
return getnumber(p, &p, a)
&& (*p != '.' || getnumber(p + 1, &p, b))
&& isblank((unsigned char)*p)
&& getnumber(skipblanks(p), &p, c))
&& (*p != '.' || getnumber(p + 1, &p, d))
&& isblank((unsigned char)*p)
&& getnumber(skipblanks(p), &p, e))
&& *skipblanks(p) == '\n';
}
int main(void) {
char buf[128];
int a, b, c, d, e;
int status;
char *p;
if (fgets(buf, sizeof buf, stdin)) {
/* set default values for b and d */
a = b = c = d = e = 0;
if (parseinput(buf, &a, &b, &c, &d, &e)) {
printf("a=%d, b=%d, c=%d, d=%d, e=%d\n, a, b, c, d, e);
} else {
printf("input format error\n");
}
} else {
printf("no input\n");
}
return 0;
}