• sscanf格式(转)


    文章转载自:https://www.cnblogs.com/clover-toeic/p/3727028.html

       sscanf()为C语言标准库函数,用于从指定字符串中读入与指定格式相符的数据。函数原型声明在stdio.h头文件中:

    int sscanf(const char *str, const char *format, ...);

         该函数根据参数format(格式化字符串)来转换参数str指向的字符串,转换后的结果存于对应的可变参数内。其返回值为按照指定格式转换符成功读入且赋值的可变参数数目(若发生匹配错误而部分成功,该数目会小于指定的参数数目,甚至为0)。若首次成功转换或错误匹配发生前输入已结束(如str为空字符串),则返回EOF。发生读取错误时也返回EOF,且设置错误码errno(如format为空指针时返回EOF并设置errno为EINVAL)。可见,通过比较该函数的返回值与指定的可变参数数目,可判断格式转换是否成功。

         format可为一个或多个{%[*] [width] [{h | l | L}]type | ' ' | ' ' | ' ' | 非%符号}格式转换符。集合中{a|b|c}表示格式符a、b、c任选其一。以中括号括起来的格式符可选。%与type为必选,所有格式符必须以%开头。

     

         以下简要说明各格式符的含义:

         1) 赋值抑制符'*'表明按照随后的转换符指示来读取输入,但将其丢弃不予赋值(“跳过”)。抑制符无需相应的指针可变参数,该转换也不计入函数返回的成功赋值次数。

    %*[width] [{h | l | L}]type 表示满足该条件的字符被过滤掉,不会向目标参数中赋值。

         2) width表示最大读取宽度。当读入字符数超过该值,或遇到不匹配的字符时,停止读取。多数转换丢弃起始的空白字符。这些被丢弃的字符及转换结果添加的空结束符('')均不计入最大读取宽度。

         3) {h | l | L}为类型修饰符。h指示输入的数字数值以short int或unsigned short int类型存储;hh指示输入以signed char或unsigned char类型存储。l(小写L)指示输入以long int、unsigned long int或double类型存储,若与%c或%s结合则指示输入以宽字符或宽字符串存储;ll等同L。L指示输入以long long类型存储。

         4) type 为类型转换符,如%s、%d。

         此外,还有两种特殊的格式符:

         1) []:字符集合。[]表示指定的字符集合匹配非空的字符序列;^则表示过滤。该操作不会跳过空白字符(空格、制表或换行符),因此可用于目标字符串不以空白字符分隔时。[]内可有一到多个非^字符(含连字符'-'),且无顺序要求。%[a-z]表示匹配a到z之间的任意字符,%[aB-]匹配a、B、-中的任一字符;%[^a]则匹配非a的任意字符,即获取第一个a之前的(不为a的)所有字符。^可作用于多个条件,如^a-z=表示^a-z且^=(既非小写字母亦非等号)。空字符集%[]和%[^]会导致不可预知的结果。

         使用[]时接收输入的参数必须是有足够存储空间的char、signed char或unsigned char数组。[]也是转换符,故%[]后无s。

       %[^]的含义和用法与正则表达式相同,故sscanf函数某种程度上提供了简单的正则表达式功能。

         2) n:至此已读入值(未必赋值)的等价字符数,该数目必须以int类型存储。如"10,22"经过"%d%*[^0-9]%n"格式转换后,%n对应的参数值为3(虽然','未参与赋值)。

         'n'并非转换符,尽管它可用'*'抑制。C标准声称,执行%n指令并不增加函数返回的赋值次数;但其勘误表中的描述与之矛盾。建议不要假设%n对返回值的影响。

     

         下表列举sscanf函数常见的格式化用法:

    原字符串

    格式化字符串

    结果字符串

    helloworld

    %s

    helloworld

    hello, world

    %s

    hello,

    hello, world

    %4s

    hell

    hello, world

    %*s%s

    world(若原字符串无空格则得到空串)

    hello, world

    %[^ ]

    hello,

    hello, world

    %[a-z]

    hello

    12345helloWORLD

    %[1-9a-z]或%[a-z1-9]

    12345hello

    12345helloWORLD

    %[^A-Z]

    12345hello

    12345helloWORLD

    %[^a-f]

    12345h

    12345helloWORLD

    %*[1-9]%[a-z]

    hello

    12345helloWORLD

    %[a-z]

    (空串,需先过滤前面不需要的字符)

    12345helloWORLD=

    %*[1-9]%*[a-z]%[^a-z=]

    WORLD

    12345/hello@world

    %*[^/]/%[^@]

    hello

    IpAddr=10.46.44.40

    %*[^=]=%s

    10.46.44.40

    Name    =   Yuan

    %*[^=]=%*[ ]%s

    Yuan

    email:wxy@zte.com.cn;

    %*[^:]:%[^;]

    wxy@zte.com.cn

    email:wxy@zte.com.cn

    %*[^:]:%s

    wxy@zte.com.cn

    wxy@zte.com.cn

    %[^@]%*c%s

    串1:wxy;串2:zte.com.cn

    IpAddr=10.46.44.40

    %[^=]=%s

    串1:IpAddr;串2:10.46.44.40

    1hello234world5

    1%[^2]234%[^5]

    串1:hello;串2:world

    Michael/nWang

    %[^/n]%*c%*c%s

    串1:Michael;串2:Wang

    Michael Wang

    %[^ ]%*c%s

    串1:Michael;串2:Wang

    13:10:29-13:11:08

    %[0-9,:] - %[0-9,:]

    串1:13:10:29;串2:13:11:08

    10.46.44.40

    %d.%d.%d.%d

    串1:10;串2:46;串3: 44;串4: 40

         此外,还有如下几种用法:

        【例1】读入一行字符串

         因字符串可能含空白字符,故不能直接使用%s;而gets函数存在溢出风险,不推荐使用。此时,可使用sscanf函数,格式化字符串设为"%[^ ]%*c"。%*c用于跳过换行符 ,以便再次读入下一行。

        【例2】提取"Name = Yuan"中的"Name"

         若行首有空白字符,可用"%*[ ]%[^= ]"格式串;

         若不确定行首有无空白字符,可先跳过空白字符:

    1 char szName[] = "Name    =   Yuan";
    2 char szResBuf[32] = {0};
    3 sscanf(szName+strspn(szName," 	"), "%[^= 	]", szResBuf);

        【例3】分解URL

         普通实现如下所示:

    复制代码
     1 /*****************************************************************************
     2  * 函数名称:OaSplitPwFarEndIpInfo
     3  * 功能描述:将远端IP信息分解为目的IP地址和端口号
     4  * 注意事项:远端IP信息应形如'udp://192.168.100.221:5000'
     5 *****************************************************************************/
     6 static FUNC_STATUS OaSplitPwFarEndIpInfo(INT8U *pucFarEndIpInfo, INT32U *dwDstUdpPort, INT8U *pucDstIpAddr)
     7 {
     8     FUNC_STATUS retCode = S_OK;
     9     INT8U  strUdpHead[] = "udp://";
    10     INT8U  ucUdpUrlLen = strlen(strUdpHead);
    11     INT8U  ucIndex = 0;
    12 
    13     CHECK_TRIPLE_POINTER(pucFarEndIpInfo, dwDstUdpPort, pucDstIpAddr, S_NULL_POINTER);
    14 
    15     if(strncasecmp(pucFarEndIpInfo, strUdpHead, ucUdpUrlLen) != 0)
    16     {
    17         OmciLog(LOG_CES,"[%s]Cannot Parse FarEndIpInfo(%s)!
    
    ", __FUNCTION__, pucFarEndIpInfo);
    18         return S_ERROR;
    19     }
    20 
    21     INT8U ucMaxUrlLen = ucUdpUrlLen + STR_IPV4_MAX_LEN; //避免未配置端口时陷入死循环(infinite loop)
    22     for(ucIndex = 0; (pucFarEndIpInfo[ucUdpUrlLen] != ':') && (ucUdpUrlLen < ucMaxUrlLen); ucIndex++)
    23     {
    24         pucDstIpAddr[ucIndex] = pucFarEndIpInfo[ucUdpUrlLen++];
    25     }
    26     pucDstIpAddr[ucIndex] = '';
    27 
    28     *dwDstUdpPort = strtoul(&pucFarEndIpInfo[ucUdpUrlLen+1], NULL, 10);
    29 
    30     return retCode;
    31 }
    复制代码

         使用sscanf格式化则更为简单:

    1 char szUrl[] = "udp://192.168.100.221:5000";
    2 char szProt[4] = {0}, szIp[32] = {0};
    3 unsigned int dwPort = 0;
    4 sscanf(szUrl, "%[^://]%*c%*c%*c%[^:]%*c%d", szProt, szIp, &dwPort);
    5 printf("szProt=%s, szIp=%s, dwPort=%d
    ", szProt, szIp, dwPort);

        【例4】提取数字

    复制代码
    1 char szDig[]="10,22m,Z86,,880;555:666."; 
    2 int dwIdx = 0, dwVal = 0, dwSize = 0;
    3 while(1 == sscanf(szDig+dwIdx, "%d%*[^0-9]%n", &dwVal, &dwSize))
    4 {
    5     dwIdx += dwSize;
    6     printf("dwIdx=%d, dwSize=%d, dwVal=%d
    ", dwIdx, dwSize, dwVal); 
    7 }
    复制代码

         上述实现稍加改造,即可用于处理某种字符分隔的数字串。

     

         综上,对于简单的字符串分析,采用sscanf函数处理比较简洁。若字符串比较复杂,则可借助相应的正则表达式库。需要注意,sscanf格式化的目的是“截取”,而正则表达式的目的是“匹配”,不能完全等同。

     

     

  • 相关阅读:
    微信小程序之某个节点距离顶部和底部的距离 createSelectorQuery
    js正则手机号 验证
    算法将一个对象中的某一个key值变为true,其他值都为false
    更改上传框的大小
    Educational Codeforces Round 85 (Div. 2)
    Codeforces Round #632 (Div. 2)
    AtCoder Beginner Contest 161
    Codeforces Round #631 (Div. 2)
    Codeforces Round #630 (Div. 2)
    Codeforces Round #629 (Div. 3)
  • 原文地址:https://www.cnblogs.com/yeshenmeng/p/13668381.html
Copyright © 2020-2023  润新知