使用sscanf()格式说明符验证电子邮件地址

使用sscanf()格式说明符验证电子邮件地址,c,email-validation,scanf,format-specifiers,C,Email Validation,Scanf,Format Specifiers,这可能是一个“修复我的代码”的问题,但我已经看了,并且,虽然我在逻辑上或多或少地理解了它是如何工作的,但我在将其转换为Csscanf()格式代码时遇到了困难。我对C语言还是比较陌生的,我刚刚开始稍微了解一些简单的东西,我很难理解更复杂的格式说明符(例如,%[^…],等等) 不管怎么说,我的情况如下: char user[EMAIL_LEN]; char site[EMAIL_LEN]; char domain[4]; if(sscanf(input, "%s@%s.%3s", user, sit

这可能是一个“修复我的代码”的问题,但我已经看了,并且,虽然我在逻辑上或多或少地理解了它是如何工作的,但我在将其转换为C
sscanf()
格式代码时遇到了困难。我对C语言还是比较陌生的,我刚刚开始稍微了解一些简单的东西,我很难理解更复杂的格式说明符(例如,
%[^…]
,等等)

不管怎么说,我的情况如下:

char user[EMAIL_LEN];
char site[EMAIL_LEN];
char domain[4];
if(sscanf(input, "%s@%s.%3s", user, site, domain) != 3){
  printf("--ERROR: Invalid email address.--\n");
}
为什么不起作用?我只是想得到一个简单的
aaaa@bbbb.ccc
格式,但由于某些原因
sscanf(输入,“%s@%s.%3s”、用户、站点、域)
总是计算为
1
。我需要使用一些疯狂的
%[^…]
魔法才能正确转换吗?我一直在处理
%[^@]
之类的事情,但我似乎无法让它工作


非常感谢您的帮助。谢谢

scanf格式的
%s
跳过前导空格,然后匹配所有非空格字符,直到下一个空格字符,但不包括下一个空格字符。因此,当您将电子邮件地址提供给它时,整个地址将被复制到
user
中,以匹配
%s
。然后,由于下一个字符不是
@
,因此不会再匹配其他字符,
scanf
返回1

您可以尝试使用以下方法:

sscanf(input, "%[^@ \t\n]@%[^. \t\n].%3[^ \t\n]", user, site, domain)
sscanf(input, "%[_a-zA-Z0-9.]@%[_a-zA-Z0-9.]", user, domain)
这会将所有内容匹配到用户的
@
或空格,然后,如果下一个字符实际上是
@
将跳过它,并将所有内容存储到
站点中的空格。但这将接受许多其他在电子邮件地址中无效的字符,并且不接受更长的域名。更好的方法可能是:

sscanf(input, "%[^@ \t\n]@%[^. \t\n].%3[^ \t\n]", user, site, domain)
sscanf(input, "%[_a-zA-Z0-9.]@%[_a-zA-Z0-9.]", user, domain)

它将接受名称和域的任何字母、数字、下划线和句点字符串。然后,如果您真的需要拆分域的最后一部分,请分别执行此操作。

%s
以scanf格式跳过前导空格,然后匹配所有非空格字符,直到下一个空格字符,但不包括下一个空格字符。因此,当您将电子邮件地址提供给它时,整个地址将被复制到
user
中,以匹配
%s
。然后,由于下一个字符不是
@
,因此不会再匹配其他字符,
scanf
返回1

您可以尝试使用以下方法:

sscanf(input, "%[^@ \t\n]@%[^. \t\n].%3[^ \t\n]", user, site, domain)
sscanf(input, "%[_a-zA-Z0-9.]@%[_a-zA-Z0-9.]", user, domain)
这会将所有内容匹配到用户的
@
或空格,然后,如果下一个字符实际上是
@
将跳过它,并将所有内容存储到
站点中的空格。但这将接受许多其他在电子邮件地址中无效的字符,并且不接受更长的域名。更好的方法可能是:

sscanf(input, "%[^@ \t\n]@%[^. \t\n].%3[^ \t\n]", user, site, domain)
sscanf(input, "%[_a-zA-Z0-9.]@%[_a-zA-Z0-9.]", user, domain)

它将接受名称和域的任何字母、数字、下划线和句点字符串。然后,如果您真的需要分割域的最后一部分,请分别进行。

@KeithThompson是的,我不确定。我想我会试试的P
“%s”
将丢弃前导空格,这不是您想要的。您还假设顶级域的长度不超过3个字符,这不再是一个有效的假设。由于
@
是非空白字符,因此第一个
%s
将占用整个电子邮件地址
sscanf
格式比正则表达式弱,而匹配有效电子邮件地址的正则表达式非常庞大,甚至不可能:。@KeithThompson我知道
aaaa@bbbb.ccc
不包含所有有效的电子邮件地址。我读了那个问题(实际上是帖子中的一个链接)和另一个关于这些东西的问题。作为一个初学者和学生,我只是想学习一下它是如何工作的。这本书对格式说明符有很好的描述。@Jason谢谢。我现在真的买不起我现在绝对不需要的课本,但我会保留那个清单供将来参考。@KeithThompson是的,我不确定。我想我会试试的P
“%s”
将丢弃前导空格,这不是您想要的。您还假设顶级域的长度不超过3个字符,这不再是一个有效的假设。由于
@
是非空白字符,因此第一个
%s
将占用整个电子邮件地址
sscanf
格式比正则表达式弱,而匹配有效电子邮件地址的正则表达式非常庞大,甚至不可能:。@KeithThompson我知道
aaaa@bbbb.ccc
不包含所有有效的电子邮件地址。我读了那个问题(实际上是帖子中的一个链接)和另一个关于这些东西的问题。作为一个初学者和学生,我只是想学习一下它是如何工作的。这本书对格式说明符有很好的描述。@Jason谢谢。我现在真的买不起我现在绝对不需要的课本,但我会保留这份清单供将来参考。好吧,这是有道理的。但是为什么要在排除部分中包含
\t\n
?我知道它们代表空白,但电子邮件地址中通常没有空白,是吗?另外,还有一个简单的问题:是否有一种方法可以在不指定变量的情况下测试格式?我认为它在某种程度上使用了
*
,但我不确定。我们在模式中包括“\t\n”,以便拒绝包含空格或制表符的内容,例如“
John”Smith@this无效
“对,这很有意义。我已经做了一个“有效字符”集来比较字符串,所以我没有想到。好的,这是有意义的。但是为什么要在排除部分中包含
\t\n
?我知道它们代表空白,但电子邮件地址中通常没有空白,是吗?另外,还有一个简单的问题:是否有一种方法可以在不指定变量的情况下测试格式?我认为它使用
*<