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

时间:2017-08-18 11:11:34

标签: c regex scanf

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

"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.我做错了什么?

2 个答案:

答案 0 :(得分:3)

  

我做错了什么?

Input:  "read 0x1234ABCD 2000"
Format: "read 0x%x[0-9a-fA-F]{8} %u[0-9]{1,4}"

输入"read 0x"与格式"read 0x"匹配。好到目前为止。

输入"1234ABCD"与格式"%x"匹配。目前很好。 +返回值。

输入" "与格式"["不匹配。扫描停止。 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原始代码的内容需要更多工作。使用"%[...]"测试允许的扫描集

#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);
  ...
}

除了我允许xX之外,我没有看到此代码没有失败/传递的输入行,除非我允许<input type="checkbox" name="day_of_week[]" value="1">Monday <input type="checkbox" name="day_of_week[]" value="2">Tuesday <input type="checkbox" name="day_of_week[]" value="3">Wednessday <input type="checkbox" name="day_of_week[]" value="4">Thursday <input type="checkbox" name="day_of_week[]" value="5">Friday <input type="checkbox" name="day_of_week[]" value="6">Saturday <input type="checkbox" name="day_of_week[]" value="7">Sunday string mysqli_real_escape_string ( mysqli $link , string $escapestr )

答案 1 :(得分:2)

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

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

这是一个更简单的版本:

 int n = sscanf(str, "read %i %i", &addr, &len);