sscanf 和 scanset 停止读取十六进制数字

Sim*_*one 5 c uuid scanf

我尝试验证 UUID v4。我尝试使用 sscanf 执行此操作,如果可以使用 sscanf 完全读取 UUID(= 读取的字符总数 - 36),我认为这是一个正确的 UUID。到目前为止我的代码:

#include <stdio.h>

int main()
{
    char uuid[ 37 ] = "da4dd6a0-5d4c-4dc6-a5e3-559a89aff639";
    int a = 0, b = 0, c = 0, d = 0, e = 0, g = 0;
    long long int f = 0;

    printf( "uuid >%s<, variables read: %d \n", uuid, sscanf( uuid, "%8x-%4x-4%3x-%1x%3x-%12llx%n", &a, &b, &c, &d, &e, &f, &g ) );
    printf( " a - %x, b - %x,  c - %x,  d - %x,  e - %x, f - %llx, total number of characters read - %d \n", a, b, c, d, e, f, g );

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

返回以下输出

uuid >da4dd6a0-5d4c-4dc6-a5e3-559a89aff639<, variables read: 6 
 a - da4dd6a0, b - 5d4c,  c - dc6,  d - a,  e - 5e3, f - 559a89aff639, total number of characters read - 36 
Run Code Online (Sandbox Code Playgroud)

到目前为止,一切都还好。现在我想包括,第三个连字符之后的第一个字符必须是 [89ab] 之一。所以我%1x%3x改为%1x[89ab]%3x. 但现在,第一个字符被读取,其余的不再读取。输出:

uuid >da4dd6a0-5d4c-4dc6-a5e3-559a89aff639<, variables read: 4 
a - da4dd6a0, b - 5d4c,  c - dc6,  d - a,  e - 0, f - 0, total number of characters read - 0 
Run Code Online (Sandbox Code Playgroud)

我缺少什么?语法有什么问题?这样读可以吗?我尝试了扫描集和说明符的几种组合,但没有任何效果。

chq*_*lie 2

sscanf()您可以编写一个简单的专用函数,而不是用于此任务:

#include <ctype.h>
#include <string.h>

int check_UUID(const char *s) {
    int i;
    for (i = 0; s[i]; i++) {
        if (i == 8 || i == 13 || i == 18 || i == 23) {
            if (s[i] != '-')
                return 0;
        } else {
            if (!isxdigit((unsigned char)s[i])) {
                return 0;
        }
    }
    if (i != 36)
        return 0;

    // you can add further tests for specific characters:
    if (!strchr("89abAB", s[19]))
        return 0;

    return 1;
}
Run Code Online (Sandbox Code Playgroud)

如果您坚持使用sscanf(),这里是简洁的实现:

#include <stdio.h>

int check_UUID(const char *s) {
    int n = 0;
    sscanf(s, "%*8[0-9a-fA-F]-%*4[0-9a-fA-F]-%*4[0-9a-fA-F]-%*4[0-9a-fA-F]-%*12[0-9a-fA-F]%n", &n);
    return n == 36 && s[n] == '\0';
}
Run Code Online (Sandbox Code Playgroud)

如果要优化第三个连字符后第一个字符的测试,请添加另一个字符类:

#include <stdio.h>

int check_UUID(const char *s) {
    int n = 0;
    sscanf(s, "%*8[0-9a-fA-F]-%*4[0-9a-fA-F]-%*4[0-9a-fA-F]-%*1[89ab]%*3[0-9a-fA-F]-%*12[0-9a-fA-F]%n", &n);
    return n == 36 && s[n] == '\0';
}
Run Code Online (Sandbox Code Playgroud)

笔记:

  • *后面的%方法不存储转换,只是跳过字符,并且1方法最多消耗1字符。
  • 对于解析的字符数sscanf达到 36,所有十六进制数字序列必须恰好具有指定的宽度。
  • %n导致scanf将到目前为止读取的字符数存储到下int一个参数所指向的位置。
  • 您的转换规范对于获取实际的 UUID 数字很有用,但该%x格式接受前导空格、可选符号和可选0x0X前缀,所有这些在 UUID 内都是无效的。您可以首先验证 UUID,然后根据需要将其转换为各个部分。