如何在C语言的sscanf函数中读取具有扫描集(如[0-9]或[a-z])的输入。我们无法成功实现一个扫描集来成功扫描字符串。
这是我的示例:
void printResult(char * test, char * actual, char * expected)
{
printf("\n\n%d. %s\r",testcount++, test);
if(strcmp(actual,expected) == 0)
{
printf("SUCCESS\r");
printf("Output:%s", actual);
}
else
{
printf("FAILED\r");
printf("Expected Output:%s Actual Output:%s", expected, actual);
}
}
int main()
{
char buffer[] = "250MEL\r";
char * pBuffer = buffer;
char output[5]={0};
//1
sscanf(pBuffer,"%[ 0-9 ]s",output);
printResult("%[0-9]s", output, "250");
//2
sscanf(pBuffer,"%3[ 0-9 ]s",output);
printResult("%3[0-9]s", output, "250");
return 0;
}
您能帮助我正确使用扫描集吗?
答案 0 :(得分:2)
TL; DR 尚不清楚是什么让您认为扫描集失败;他们在这种情况下对我来说工作正常。下面显示的经过稍加修改的代码就说明了这一点。
正如我在comment中所指出的,扫描集的格式为%[…]
-停止于]
以及后面代码中{s
之后的任何内容问题)不属于扫描集。如果需要在扫描集中包含]
,则它必须是第一个字符(如果使用的是否定的扫描集,则它必须是否定插入符号的插入号之后)。对于扫描集之后的s
,如果输入在数字和空白序列的末尾包含s
(扫描集中的第一个空白是有效的;第二个是重复的,则为否),那么该字符将被“消耗”,并且下一个输入操作将在s
之后继续;如果下一个字符不是s
,则将其保留在输入中以进行下一个输入操作。另外,如果下一个字符不是s
,则匹配失败,但是当扫描集是格式字符串中的最后一个转换规范或唯一的转换规范时,sscanf()
无法报告。尾随上下文始终是消耗性的;
您的代码很奇怪,因为它在许多地方都使用\r
。您将很少需要在C代码中使用\r
-您应该在代码中使用\n
(或空白,或…)。
这是一个与您的程序紧密相关的程序,但有所更改。该代码检查sscanf()
的返回值;它用其他一些字符替换了大多数回车符;保留错误的格式字符串;它使print函数的参数与sscanf()
函数的参数匹配。
#include <stdio.h>
#include <string.h>
static int testcount = 1;
static void printResult(char *test, char *actual, char *expected)
{
printf("\n\n%d. [%s]: ", testcount++, test);
if (strcmp(actual, expected) == 0)
{
printf("SUCCESS ");
printf("Output: [%s]\n", actual);
}
else
{
printf("FAILED ");
printf("Expected Output: [%s], Actual Output: [%s]\n", expected, actual);
}
}
int main(void)
{
char buffer[] = "250MEL\r";
char *pBuffer = buffer;
char output[5] = {0};
// 1
if (sscanf(pBuffer, "%[ 0-9 ]s", output) != 1)
printf("scanf() 1 failed\n");
printResult("%[ 0-9 ]s", output, "250");
// 2
if (sscanf(pBuffer, "%3[ 0-9 ]s", output) != 1)
printf("scanf() 1 failed\n");
printResult("%3[ 0-9 ]s", output, "250");
return 0;
}
它还会产生预期的输出:
1. [%[ 0-9 ]s]: SUCCESS Output: [250]
2. [%3[ 0-9 ]s]: SUCCESS Output: [250]
如果以前没有看到SUCCESS
,那是因为\r
字符将书写位置移到了行首,所以随后的内容覆盖了SUCCESS
。
另外,请让我知道如何为A-Z设置一个范围,如下所示-但这不起作用:
sscanf(pBuffer,"%*[A-Z]s",output); printResult("%[A-Z]s",output, "MEL" );
请注意!
您的评论表明您仍然认为%[…]s
是扫描集的表示法,但是s
是虚假的;它不是扫描集符号的一部分。停止将%[…]
视为%s
的修饰符;它不是修饰符。它是一个完全独立的转换规范,几乎与%s
无关,并且在语法上与printf()
完全不同。方括号表示在类别上也明确地不是任何标准#include <stdio.h>
#include <string.h>
static int strings_match(const char *actual, const char *expected);
static void printResult(const char *format, const char *data, const char *act1,
char *exp1, const char *act2, char *exp2);
int main(void)
{
char buffer1[] = "250MEL@93";
char buffer2[] = " 250 \t\tMELabc";
char number[5] = "";
char letters[5] = "";
const char fmt1[] = "%4[0-9]%4[A-Z]";
const char fmt2[] = " %4[0-9] %4[A-Z]";
if (sscanf(buffer1, fmt1, number, letters) != 2)
printf("sscanf() 1 failed\n");
else
printResult(fmt1, buffer1, number, "250", letters, "MEL");
if (sscanf(buffer2, fmt2, number, letters) != 2)
printf("sscanf() 2 failed\n");
else
printResult(fmt2, buffer2, number, "250", letters, "MEL");
number[0] = '\0';
letters[0] = '\0';
if (sscanf(buffer2, fmt1, number, letters) != 2)
printf("sscanf() 3 failed\n");
else
printResult(fmt2, buffer1, number, "250", letters, "MEL");
const char fmt3[] = "%4[0-9]s%c";
const char fmt4[] = "%4[0-9]%c";
char buffer3[] = "9876sun";
char buffer4[] = "9876moon";
char letter;
if (sscanf(buffer3, fmt3, number, &letter) != 2)
printf("sscanf() 4 failed\n");
else
printf("Data [%s], Format [%s], Output [%s] %c\n", buffer3, fmt3, number, letter);
if (sscanf(buffer3, fmt4, number, &letter) != 2)
printf("sscanf() 5 failed\n");
else
printf("Data [%s], Format [%s], Output [%s] %c\n", buffer3, fmt4, number, letter);
if (sscanf(buffer4, fmt3, number, &letter) != 2)
printf("sscanf() 6 failed\n");
else
printf("Data [%s], Format [%s], Output [%s] %c\n", buffer4, fmt3, number, letter);
return 0;
}
static int strings_match(const char *actual, const char *expected)
{
int rc;
if (strcmp(actual, expected) == 0)
{
rc = 1;
printf(" Output: [%s]", actual);
}
else
{
rc = 0;
printf(" Expected Output: [%s], Actual Output: [%s]", expected, actual);
}
return rc;
}
static int testcount = 1;
static void printResult(const char *format, const char *data, const char *act1,
char *exp1, const char *act2, char *exp2)
{
printf("Format: %d. [%s] Data: [%s]", testcount++, format, data);
int t1 = strings_match(act1, exp1);
int t2 = strings_match(act2, exp2);
if (t1 == 1 && t2 == 1)
printf(" - SUCCESS\n");
else
printf(" - FAILED\n");
}
转换规范语法的一部分。
这里有一些修改的代码是根据答案的前一部分(因此是根据问题中的代码)松散地进行的。它不是恒星,但确实显示了一些有用的信息。
Format: 1. [%4[0-9]%4[A-Z]] Data: [250MEL@93] Output: [250] Output: [MEL] - SUCCESS
Format: 2. [ %4[0-9] %4[A-Z]] Data: [ 250 MELabc] Output: [250] Output: [MEL] - SUCCESS
sscanf() 3 failed
Data [9876sun], Format [%4[0-9]s%c], Output [9876] u
Data [9876sun], Format [%4[0-9]%c], Output [9876] s
sscanf() 6 failed
输出:
s
请注意最后两个成功的转换行之间的区别-格式字符串中的u
作为文字与数据进行匹配,与之相比,s
被读入字符格式字符串中没有s
,并且字符与s
相匹配。相反,当格式寻找m
并找到sscanf()
时,整个{{1}}就会失败—它只能管理1个而不是2个转换规范。