使用sscanf从格式化字符串读取多个值

使用sscanf从格式化字符串读取多个值,c,regex,scanf,C,Regex,Scanf,我试图从一个字符串中提取两个值。第一个是8位十六进制值,第二个是无符号1-4位值。这些值之前还应该有一个命令,告诉程序如何处理这些值,在本例中为“读取”。格式的一些示例: "read 0x1234ABCD 2000" "read 0x00000001 10" 我希望提取这两个值并确认格式,并具有以下代码行: uint addr; uint len; int n = sscanf(str, "read 0x%x[0-9a-fA-F]{8} %u[0-9]{1,4}", &addr, &

我试图从一个字符串中提取两个值。第一个是8位十六进制值,第二个是无符号1-4位值。这些值之前还应该有一个命令,告诉程序如何处理这些值,在本例中为“读取”。格式的一些示例:

"read 0x1234ABCD 2000"
"read 0x00000001 10"
我希望提取这两个值并确认格式,并具有以下代码行:

uint addr;
uint len;

int n = sscanf(str, "read 0x%x[0-9a-fA-F]{8} %u[0-9]{1,4}", &addr, &len);

if (n != 2){
    // Wrong format...
}

十六进制值读取正确,但第二个值不正确,n始终为1。我做错了什么?

要解析十六进制和十进制编码的数字,请使用
%I
转换说明符

无法使用格式字符串中使用的正则表达式语法指定位数,这解释了第二次转换失败的原因

以下是一个更简单的版本:

 int n = sscanf(str, "read %i %i", &addr, &len);
我做错了什么

输入
“read 0x”
与格式
“read 0x”
匹配。到目前为止还不错

输入
“1234ABCD”
与格式
“%x”
匹配。到目前为止还不错+返回值为1

输入
与格式
”[“
不匹配。扫描停止。
sscanf()
返回1


或者,将第二个值读取为十进制值

const char *f1 = "read 0x%x %u";
const char *f2 = "read 0x%x%u";   // Space not need, yet looks good
const char *f3 = "read %x%u";     // Always read addr as hex, even with/without 0x
const char *f4 = "read %x %u";
const char *f5 = "read%x%u";

unsigned addr;
unsigned len;
int n = sscanf(str, fn, &addr, &len);  // select format from above
上述代码不会失败

"read 0x0x123 +1234"
"read 0x123 456 xyz"
"read 0x123 12345"
"read 0x+123 -123"

OP应该需要更多的错误检查。8将
addr
的文本输入限制为8个非空白字符。
sentinel
检测尾随的非空白垃圾

unsigned addr;
unsigned len;
char sentinel;
int n = sscanf(str, "read 0x%8x %4u %c", &addr, &len, &sentinel);
if (n != 2){
  // Wrong format...
}
上述措施确实失败了

"read 0x123 456 xyz"

最接近原始代码的内容需要更多的工作。使用
“%[…]”
测试允许的扫描集


我看不到任何一行输入代码不会像OP所希望的那样失败/通过,除了我允许
x
x

scanf
不做正则表达式。要读取多达八个十六进制数字,只需使用
%8x
。例如,@Someprogrammerdude.Hmm,我想知道这个答案()。这不是正则表达式吗?假设你的意思是“%[0-9]”,那么它不是正则表达式,但它是一个使用简单字符类的变体。好的,我在sscanf“read 0x%8x%u”中尝试了以下方法,效果很好。谢谢!@AndrewHenle Agree
scanf()
可能是一个挑战,但更大的挑战,IMO,是语法要求从一开始就不完整:只提供一些可接受的表单和一些不可接受的表单。当允许原始目标不精确时,任何解决方案都容易出现维护问题。第一个%i真的能确保将值解析为十六进制?我知道数字是否有A-F字符,但如果数字是“00000010”怎么办?这将被解读为16还是10?@Martin--您的问题的答案在文档中。
%i
希望输入的格式为。
00000010
将被解读为八进制数字,十进制数字为8。如果您希望输入被解读为十六进制,请使用
0x00000010
0x00000010
。请注意错误检查版本输入
“读取0x75088FF08”
@DavidBowling时不会失败请参见编辑
"read 0x123 456 xyz"
#define F_RD    "read"
#define F_SP    "%*[ ]"
#define F_ADDR  "0x%8[0-9a-fA-F]"
#define F_LEN   "%4[0-9]"
#define F_SEN   " %c"
char addr_s[8+1];
char len_s[4+1];
char sentinel;
int n = sscanf(str, F_RD F_SP F_ADDR F_SP F_LEN F_SEN, addr_s, len_s, &sentinel);
if (n == 2){
  // Success
  unsigned long addr = strtoul(addr_s, (char **)NULL, 16);
  unsigned len = strtoul(len_s, (char **)NULL, 10);
  ...
}