C if 语句,检查特殊字符和字母的最佳方法
C if statement, optimal way to check for special characters and letters
大家好,在此先感谢您的帮助,我正在学习 CS50 课程,我才刚刚开始编程。
我想检查主函数参数 string argv[]
中的字符串是否确实是一个数字,我搜索了多种方法。
我在另一个主题How can I check if a string has special characters in C++ effectively?中找到了用户Jerry Coffin发布的解决方案:
char junk;
if (sscanf(str, "%*[A-Za-z0-9_]%c", &junk))
/* it has at least one "special" character
else
/* no special characters */
如果在我看来它可能适用于我正在尝试做的事情,我不熟悉 sscanf
函数,我很难集成和适应我的代码,我走到这一步我无法理解我错误的逻辑:
#include <cs50.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
int numCheck(string[]);
int main(int argc, string argv[]) {
//Function to check for user "cooperation"
int key = numCheck(argv);
}
int numCheck(string input[]) {
int i = 0;
char junk;
bool usrCooperation = true;
//check for user "cooperation" check that key isn't a letter or special sign
while (input[i] != NULL) {
if (sscanf(*input, "%*[A-Za-z_]%c", &junk)) {
printf("test fail");
usrCooperation = false;
} else {
printf("test pass");
}
i++;
}
return 0;
}
让我们再试一次:
这仍然是你的问题:
if (sscanf(*input, "%*[A-Za-z_]%c", &junk))
但不是因为我最初所说的原因 - *input
等于 input[0]
。你想要的
if ( sscanf( input[i], "%*[A-Za-z_]%c", &junk ) )
您正在做的是在 while 循环中遍历所有命令行参数:
while( input[i] != NULL )
但您实际上只是在 测试 input[0]
.
所以,快速入门 sscanf
:
第一个参数 (input
) 是您要扫描的字符串。此参数的类型需要为 char *
(指向 char
的指针)。 string
typedef 名称是 char *
的别名。 CS50 试图掩盖 C 字符串处理的粗略部分,I/O 和 string
typedef 是其中的一部分,但它是 CS50 课程所独有的,而不是该语言的一部分。当心。
第二个参数是格式字符串。 %[
和 %c
是格式说明符,它们告诉 sscanf
您要在字符串中查找什么。 %[
指定一组称为扫描集的字符 - %[A-Za-z_]
表示“匹配任何大小写字母和下划线序列”。 %*[A-Za-z_]
中的 *
表示不要将扫描结果分配给参数。 %c
匹配任何字符。
其余参数是您要存储的输入项,它们的类型必须与格式说明符匹配。 %[
期望其对应的参数具有类型 char *
并且是将存储输入的数组的地址。 %c
期望其相应的参数(在本例中为 junk
)也具有类型 char *
,但它期望单个 char
对象的地址。
sscanf
returns 成功读取和分配的项目数 - 在这种情况下,您期望 return 值是 0
或 1
(因为只有 junk
被分配给)。
综合起来,
sscanf( input, "%*[A-Za-z_]%c", &junk )
将读取并丢弃 input
中的字符,直到它看到字符串终止符或 不是 扫描集一部分的字符。如果它看到一个不属于扫描集的字符(例如数字),则该字符将写入 junk
和 sscanf
returns 1
,在此上下文被视为“真”。如果它没有看到扫描集之外的任何字符,则不会将任何内容写入 junk
和 sscanf
returns 0
,这将被视为“假”。
编辑
所以,chqrlie 指出了我的一个大错误 - 这个测试不会按预期进行。
如果 input[i]
中没有非字母和非下划线字符,则不会向 junk
和 sscanf
分配任何内容 returns 0(未分配任何内容).如果 input[i]
以字母或下划线开头,但后面包含非字母或非下划线字符,则该错误字符将被转换并分配给 junk
,而 sscanf
将 return 1
.
到目前为止一切顺利,这就是您想要发生的事情。但是...
如果input[i]
以非字母或非下划线字符开始,那么您匹配失败并且sscanf
退出,returning 0。因此它将错误地 匹配错误的输入。
坦率地说,这不是测试是否存在“不良”字符的好方法。
一个可能更好的方法是使用这样的东西:
while ( input[i] )
{
bool good = true;
/**
* Cycle through each character in input[i] and
* check to see if it's a letter or an underscore;
* if it isn't, we set good to false and break out of
* the loop.
*/
for ( char *c = input[i]; *c; c++ )
{
if ( !isalpha( *c ) && *c != '_' )
{
good = false;
break;
}
}
if ( !good )
{
puts( "test fails" );
usrCooperation = 0;
}
else
{
puts( "test passes" );
}
}
您将 argv
传递给 numcheck
并测试其中的所有字符串:这是不正确的,因为 argv[0]
是 运行 可执行文件的名称,因此您应该跳过这个论点。另请注意,您应该将 input[i]
传递给 sscanf()
,而不是 *input
.
再分析一下sscanf(input[i], "%*[A-Za-z_]%c", &junk)
的return值:
- it returns
EOF
如果输入字符串为空,
- 它 returns
0
如果 %*[A-Za-z_]
失败,
- 如果在
%*[A-Za-z_]
成功后转换 %c
失败,returns 0
,
- 它returns
1
是两个转换都成功了。
这个测试不足以检查字符串中的非数字,它实际上没有提供有用的信息:对于字符串 "1"
,return 值将是 0
并且对于字符串 "a"
...
sscanf()
非常 棘手,充满怪癖和陷阱。绝对不是模式匹配的正确工具。
如果目标是检查字符串是否仅包含数字(至少一个),请改用它,使用经常被忽视的标准函数 strspn()
:
#include <stdio.h>
#include <string.h>
int numCheck(char *input[]) {
int i;
int usrCooperation = 1;
//check for user "cooperation" check that key isn't a letter or special sign
for (i = 1; input[i] != NULL; i++) {
// count the number of matching character at the beginning of the string
int ndigits = strspn(input[i], "0123456789");
// check for at least 1 digit and no characters after the digits
if (ndigits > 0 && input[i][ndigits] == '[=10=]') {
printf("test passes: %d digits\n", ndigits);
} else {
printf("test fails\n");
usrCooperation = 0;
}
}
return usrCooperation;
}
check if the string from the main function parameter string argv[] is indeed a number
测试 字符串 是否转换为 int
的直接方法是使用 strtol()
。这很好地处理了“123”、“-123”、“+123”、“1234567890123”、“x”、“123x”、“”。
int numCheck(const char *s) {
char *endptr;
errno = 0; // Clear error indicator
long num = strtol(s, &endptr, 0);
if (s == endptr) return 0; // no conversion
if (*endptr) return 0; // Junk after the number
if (errno) return 0; // Overflow
if (num > INT_MAX || num < INT_MIN) return 0; // int Overflow
return 1; // Success
}
int main(int argc, string argv[]) {
// Call each arg[] starting with `argv[1]`
for (int a = 1; a < argc; a++) {
int success = numCheck(argv[a]);
printf("test %s\n", success ? "pass" : "fail");
}
}
sscanf(*input, "%*[A-Za-z_]%c", &junk)
是测试数值转换的错误方法。
我遵循了用户“chux - Reinstate Monica”的解决方案。感谢大家帮助我解决这个问题。这是我的最终程序,也许它可以帮助将来的其他学习者。我决定避免使用非标准库“cs50.h”。
//#include <cs50.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>
void keyCheck(int);
int numCheck(char*);
int main(int argc, char* argv[])
{
//Error code == 1;
int key = 0;
keyCheck(argc); //check that two parameters where sent to main.
key = numCheck(argv[1]); //Check for user "cooperation".
return 0;
}
//check for that main received two parameters.
void keyCheck(int key)
{
if (key != 2) //check that main argc only has two parameter. if not terminate program.
{
exit(1);
}
}
//check that the key (main parameter (argv [])) is a valid number.
int numCheck(char* input)
{
char* endptr;
errno = 0;
long num = strtol(input, &endptr, 0);
if (input == endptr) //no conversion is possible.
{
printf("Error: No conversion possible");
return 1;
}
else if (errno == ERANGE) //Input out of range
{
printf("Error: Input out of range");
return 1;
}
else if (*endptr) //Junk after numeric text
{
printf("Error: data after main parameter");
return 1;
}
else //conversion succesfull
{
//verify that the long int is in the integer limits.
if (num >= INT_MIN && num <= INT_MAX)
{
return num;
}
//if the main parameter is bigger than an int, terminate program
else
{
printf("Error key out of integer limits");
exit(1);
}
}
/* else
{
printf("Success: %ld", num);
return num;
} */
}
大家好,在此先感谢您的帮助,我正在学习 CS50 课程,我才刚刚开始编程。
我想检查主函数参数 string argv[]
中的字符串是否确实是一个数字,我搜索了多种方法。
我在另一个主题How can I check if a string has special characters in C++ effectively?中找到了用户Jerry Coffin发布的解决方案:
char junk;
if (sscanf(str, "%*[A-Za-z0-9_]%c", &junk))
/* it has at least one "special" character
else
/* no special characters */
如果在我看来它可能适用于我正在尝试做的事情,我不熟悉 sscanf
函数,我很难集成和适应我的代码,我走到这一步我无法理解我错误的逻辑:
#include <cs50.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
int numCheck(string[]);
int main(int argc, string argv[]) {
//Function to check for user "cooperation"
int key = numCheck(argv);
}
int numCheck(string input[]) {
int i = 0;
char junk;
bool usrCooperation = true;
//check for user "cooperation" check that key isn't a letter or special sign
while (input[i] != NULL) {
if (sscanf(*input, "%*[A-Za-z_]%c", &junk)) {
printf("test fail");
usrCooperation = false;
} else {
printf("test pass");
}
i++;
}
return 0;
}
让我们再试一次:
这仍然是你的问题:
if (sscanf(*input, "%*[A-Za-z_]%c", &junk))
但不是因为我最初所说的原因 - *input
等于 input[0]
。你想要的
if ( sscanf( input[i], "%*[A-Za-z_]%c", &junk ) )
您正在做的是在 while 循环中遍历所有命令行参数:
while( input[i] != NULL )
但您实际上只是在 测试 input[0]
.
所以,快速入门 sscanf
:
第一个参数 (input
) 是您要扫描的字符串。此参数的类型需要为 char *
(指向 char
的指针)。 string
typedef 名称是 char *
的别名。 CS50 试图掩盖 C 字符串处理的粗略部分,I/O 和 string
typedef 是其中的一部分,但它是 CS50 课程所独有的,而不是该语言的一部分。当心。
第二个参数是格式字符串。 %[
和 %c
是格式说明符,它们告诉 sscanf
您要在字符串中查找什么。 %[
指定一组称为扫描集的字符 - %[A-Za-z_]
表示“匹配任何大小写字母和下划线序列”。 %*[A-Za-z_]
中的 *
表示不要将扫描结果分配给参数。 %c
匹配任何字符。
其余参数是您要存储的输入项,它们的类型必须与格式说明符匹配。 %[
期望其对应的参数具有类型 char *
并且是将存储输入的数组的地址。 %c
期望其相应的参数(在本例中为 junk
)也具有类型 char *
,但它期望单个 char
对象的地址。
sscanf
returns 成功读取和分配的项目数 - 在这种情况下,您期望 return 值是 0
或 1
(因为只有 junk
被分配给)。
综合起来,
sscanf( input, "%*[A-Za-z_]%c", &junk )
将读取并丢弃 input
中的字符,直到它看到字符串终止符或 不是 扫描集一部分的字符。如果它看到一个不属于扫描集的字符(例如数字),则该字符将写入 junk
和 sscanf
returns 1
,在此上下文被视为“真”。如果它没有看到扫描集之外的任何字符,则不会将任何内容写入 junk
和 sscanf
returns 0
,这将被视为“假”。
编辑
所以,chqrlie 指出了我的一个大错误 - 这个测试不会按预期进行。
如果 input[i]
中没有非字母和非下划线字符,则不会向 junk
和 sscanf
分配任何内容 returns 0(未分配任何内容).如果 input[i]
以字母或下划线开头,但后面包含非字母或非下划线字符,则该错误字符将被转换并分配给 junk
,而 sscanf
将 return 1
.
到目前为止一切顺利,这就是您想要发生的事情。但是...
如果input[i]
以非字母或非下划线字符开始,那么您匹配失败并且sscanf
退出,returning 0。因此它将错误地 匹配错误的输入。
坦率地说,这不是测试是否存在“不良”字符的好方法。
一个可能更好的方法是使用这样的东西:
while ( input[i] )
{
bool good = true;
/**
* Cycle through each character in input[i] and
* check to see if it's a letter or an underscore;
* if it isn't, we set good to false and break out of
* the loop.
*/
for ( char *c = input[i]; *c; c++ )
{
if ( !isalpha( *c ) && *c != '_' )
{
good = false;
break;
}
}
if ( !good )
{
puts( "test fails" );
usrCooperation = 0;
}
else
{
puts( "test passes" );
}
}
您将 argv
传递给 numcheck
并测试其中的所有字符串:这是不正确的,因为 argv[0]
是 运行 可执行文件的名称,因此您应该跳过这个论点。另请注意,您应该将 input[i]
传递给 sscanf()
,而不是 *input
.
再分析一下sscanf(input[i], "%*[A-Za-z_]%c", &junk)
的return值:
- it returns
EOF
如果输入字符串为空, - 它 returns
0
如果%*[A-Za-z_]
失败, - 如果在
%*[A-Za-z_]
成功后转换%c
失败,returns0
, - 它returns
1
是两个转换都成功了。
这个测试不足以检查字符串中的非数字,它实际上没有提供有用的信息:对于字符串 "1"
,return 值将是 0
并且对于字符串 "a"
...
sscanf()
非常 棘手,充满怪癖和陷阱。绝对不是模式匹配的正确工具。
如果目标是检查字符串是否仅包含数字(至少一个),请改用它,使用经常被忽视的标准函数 strspn()
:
#include <stdio.h>
#include <string.h>
int numCheck(char *input[]) {
int i;
int usrCooperation = 1;
//check for user "cooperation" check that key isn't a letter or special sign
for (i = 1; input[i] != NULL; i++) {
// count the number of matching character at the beginning of the string
int ndigits = strspn(input[i], "0123456789");
// check for at least 1 digit and no characters after the digits
if (ndigits > 0 && input[i][ndigits] == '[=10=]') {
printf("test passes: %d digits\n", ndigits);
} else {
printf("test fails\n");
usrCooperation = 0;
}
}
return usrCooperation;
}
check if the string from the main function parameter string argv[] is indeed a number
测试 字符串 是否转换为 int
的直接方法是使用 strtol()
。这很好地处理了“123”、“-123”、“+123”、“1234567890123”、“x”、“123x”、“”。
int numCheck(const char *s) {
char *endptr;
errno = 0; // Clear error indicator
long num = strtol(s, &endptr, 0);
if (s == endptr) return 0; // no conversion
if (*endptr) return 0; // Junk after the number
if (errno) return 0; // Overflow
if (num > INT_MAX || num < INT_MIN) return 0; // int Overflow
return 1; // Success
}
int main(int argc, string argv[]) {
// Call each arg[] starting with `argv[1]`
for (int a = 1; a < argc; a++) {
int success = numCheck(argv[a]);
printf("test %s\n", success ? "pass" : "fail");
}
}
sscanf(*input, "%*[A-Za-z_]%c", &junk)
是测试数值转换的错误方法。
我遵循了用户“chux - Reinstate Monica”的解决方案。感谢大家帮助我解决这个问题。这是我的最终程序,也许它可以帮助将来的其他学习者。我决定避免使用非标准库“cs50.h”。
//#include <cs50.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>
void keyCheck(int);
int numCheck(char*);
int main(int argc, char* argv[])
{
//Error code == 1;
int key = 0;
keyCheck(argc); //check that two parameters where sent to main.
key = numCheck(argv[1]); //Check for user "cooperation".
return 0;
}
//check for that main received two parameters.
void keyCheck(int key)
{
if (key != 2) //check that main argc only has two parameter. if not terminate program.
{
exit(1);
}
}
//check that the key (main parameter (argv [])) is a valid number.
int numCheck(char* input)
{
char* endptr;
errno = 0;
long num = strtol(input, &endptr, 0);
if (input == endptr) //no conversion is possible.
{
printf("Error: No conversion possible");
return 1;
}
else if (errno == ERANGE) //Input out of range
{
printf("Error: Input out of range");
return 1;
}
else if (*endptr) //Junk after numeric text
{
printf("Error: data after main parameter");
return 1;
}
else //conversion succesfull
{
//verify that the long int is in the integer limits.
if (num >= INT_MIN && num <= INT_MAX)
{
return num;
}
//if the main parameter is bigger than an int, terminate program
else
{
printf("Error key out of integer limits");
exit(1);
}
}
/* else
{
printf("Success: %ld", num);
return num;
} */
}