C/C++ scanf/sscanf使用簡易正則(正規)表達式

C/C++ scanf/sscanf使用簡易正則(正規)表達式

C/C++ scanf/sscanf使用簡易正則(正規)表達式


資料來源:https://www.itdaan.com/tw/38e38b9edcc6640bb23d694dcd9a2cfd


線上執行: https://www.tutorialspoint.com/compile_cpp_online.php


程式碼:

#include <iostream>
#include <stdio.h>
using namespace std;

int main()
{
   cout << "Hello World" << endl; 
   char name[20], tel[50], field[20], areaCode[20], code[20];
   int age;
   sscanf("name:john age:40 tel:082-313530", "%s", name);
   printf("%s\n", name);
   sscanf("name:john age:40 tel:082-313530", "%8s", name);
   printf("%s\n", name);
   sscanf("name:john age:40 tel:082-313530", "%[^:]", name);
   printf("%s\n", name);
   sscanf("name:john age:40 tel:082-313530", "%[^:]:%s", field, name);
   printf("%s %s\n", field, name);
   sscanf("name:john age:40 tel:082-313530", "name:%s age:%d tel:%s", name, &age, tel);
   printf("%s %d %s\n", name, age, tel);
   sscanf("name:john age:40 tel:082-313530", "%*[^:]:%s %*[^:]:%d %*[^:]:%s", name, &age, tel);
   printf("%s %d %s\n", name, age, tel);
  
   char protocol[10], site[50], path[50];
   sscanf("http://ccckmit.wikidot.com/cp/list/hello.txt", 
         "%[^:]:%*2[/]%[^/]/%[a-zA-Z0-9._/-]", 
         protocol, site, path);
   printf("protocol=%s site=%s path=%s\n", protocol, site, path);   
   return 0;
}
/*output
Hello World
name:john
name:joh
name
name john
john 40 082-313530
john 40 082-313530
protocol=http site=ccckmit.wikidot.com path=cp/list/hello.txt
*/

程式碼解析

01.您應該可以看到,在上述程式碼當中,所有的 %s, %d 等輸入欄位,預設都是以空白做為結尾的,例如以下指令就只會掃描到 name=”name:john”,因為後面是空白了,所以就把 %s 的內容丟到了變數 name 當中。

  sscanf(“name:john age:40 tel:082-313530”, “%s”, name);
  printf(“%s\n”, name);

02.如果我們在 %s 等樣式中指定長度,像是以下這個 sscanf 所採用的 %8s,那麼掃描到 8 個字元之後就會停止了,所以此時 name=”name:joh” 。

  sscanf(“name:john age:40 tel:082-313530”, “%8s”, name);
  printf(“%s\n”, name);

03.但是我們可以透過類似正規表達式的語法,來設定掃描的方式,舉例而言,像是以下的 sscanf 所採用的 %[^:] ,就讓我們 可以掃描到 : 符號為止,其中的樣式 [^abc] 符號代表不要比對 a, b, c 這些字元,所以 [^:] 代表的是不可比對到 : 這個符號,因此就會在比對到該符號時停止了。於是掃描的結果會是 name=”name” 。

  sscanf(“name:john age:40 tel:082-313530”, “%[^:]”, name);
  printf(“%s\n”, name);

04.當然、這些 %s, %d 等樣式之間還可以串接,以便進行連續掃描,因此下面這個 sscanf 指令可以一次掃出 field 與 name 兩個欄位, 結果會是 field=”name”, name=”john” 。

  sscanf(“name:john age:40 tel:082-313530”, “%[^:]:%s”, field, name);
  printf(“%s %s\n”, field, name);

05.而且、在掃描到整數或浮點等非字串欄位時,還會將掃描到的結果轉為該型態放入變數中,例如下列 sscanf 指令中的 &age 欄位, 就會直接得到整數值,不需要像一般正規表達式那樣還需要經過轉型才能使用。

  sscanf(“name:john age:40 tel:082-313530”, “name:%s age:%d tel:%s”, name, &age, tel);
  printf(“%s %d %s\n”, name, age, tel);

06.如果我們希望某些欄位在掃描後,直接丟棄而不要存入任何變數中,那麼就可以用 %*… 這種加上 * 號的格式,此時 sscanf 會知道要將該欄位丟棄,不要存入到後面的變數裏。

  sscanf(“name:john age:40 tel:082-313530”, “%*[^:]:%s %*[^:]:%d %*[^:]:%s”, name, &age, tel);
  printf(“%s %d %s\n”, name, age, tel);

07.甚至、我們可以真的把 sscanf 當成「正規表達式」使用,只是語法稍有差異,功能也不像正規表達式那麼強,不過通常也夠用了。
舉例而言,以下的 sscanf 可以將一個網址剖析成 protocol, site, path 等三個段落,您可以看到我們使用的 “%[^:]:%*2[/]%[^/]/%[a-zA-Z0-9._/-]” 這個樣式,看起來是不是真的很像「正規表達式」呢?

  char protocol[10], site[50], path[50];
  sscanf(“http://ccckmit.wikidot.com/cp/list/hello.txt”, 
         “%[^:]:%*2[/]%[^/]/%[a-zA-Z0-9._/-]”, 
         protocol, site, path);
  printf(“protocol=%s site=%s path=%s\n”, protocol, site, path);

2 thoughts on “C/C++ scanf/sscanf使用簡易正則(正規)表達式

  1. sscanf/scanf正則用法

    https://www.jb51.net/article/138506.htm

    %[ ] 的用法:

    %[ ] 表示要讀入一個字符集合, 如果[ 後面第一個字符是”^” ,則表示反意思。

    [ ] 內的字符串可以是1 或更多字符組成。空字符集( %[] )是違反規定的,可導致不可預知的結果。%[^] 也是違反規定的。

  2. https://www.jb51.net/article/138506.htm

    範例

    讀取在a~z之間的字符串,如果不在此之前則停止,如
    char s[]=”hello, my friend” ; // 注意 : , 逗号在不 a-z 之间
    sscanf( s, “%[a-z]”, string ) ; // string=hello

    讀取不在az之間的字符串,如果碰到az之間的字符則停止,如
    char s[]=”HELLOkitty”;// 注意 : , 逗号在不 a-z 之间
    sscanf( s, “%[^a-z]”, string ) ; // string=HELLO

    前面帶*號表示不保存變量。跳過符合條件的字符串
    char s[]=”notepad=1.0.0.1001″ ;
    char szfilename [32] = “” ;
    int i = sscanf( s, “%*[^=]”, szfilename ) ; // szfilename=NULL, 因为没保存
    int i = sscanf( s, “%*[^=]=%s”, szfilename ) ; // szfilename=1.0.0.1001

    char s[]=”notepad=1.0.0.1001″ ;
    char szfilename [32] = “” ;
    int i = sscanf( s, “%[^=]”, szfilename ) ; // szfilename=notepad

    字串切成2段
    char s[]=”notepad=1.0.0.1001″ ;
    char szname [32] = “” ;
    char szver [32] = “” ;
    sscanf( s, “%[^=]=%s”, szname , szver ) ; // szname=notepad, szver=1.0.0.1001

發表迴響

你的電子郵件位址並不會被公開。 必要欄位標記為 *