sscanf函數和正則表達式

看了幾篇介紹sscanf函數,真是發現本身好多東西沒理解透,詳細介紹使用在sscanf中使用正則表達式。正則表達式

第一篇:函數

此文全部的實驗都是基於下面的程序:google

char str[10];spa

for (int i = 0; i < 10; i++) str[i] = '!';.net

執行完後str的值爲code

str = "!!!!!!!!!!"orm

咱們把str的每一個字符都初始化爲驚歎號,當str的值發生變化時,使用printf打印str的值,對比先前的驚歎號,這樣就能夠方便的觀察str發生了怎樣的變化。下面咱們作幾個小實驗,看看使用sscanf和正則表達式格式化輸入後,str有什麼變化。blog

實驗1:ip

 sscanf( "123456" , "%s" , str) ; ---------str的值爲 "123456\0!!!"字符串

這個實驗很簡單,把源字符串"123456"拷貝到str的前6個字符,而且把str的第7個字符設爲null字符,也就是\0

實驗2:

 sscanf( "123456" , "%3s" , str) ; ---------str的值爲 "123\0!!!!!!"

看到沒有,正則表達式的百分號後面多了一個3,這告訴sscanf只拷貝3個字符給str,而後把第4個字符設爲null字符。

實驗3:

 sscanf( "aaaAAA" , "%[a-z]" , str) ; ---------str的值爲 "aaa\0!!!!!!"

從這個實驗開始咱們會使用正則表達式,括號裏面的a-z就是一個正則表達式,它能夠表示從a到z的任意字符,

在繼續討論以前,咱們先來看看百分號表示什麼意思,%表示選擇 ,%後面的是條件,好比實驗1的"%s",s是一個條件,表示任意字符,"%s"的意思是:只要輸入的東西是一個字符,就把它拷貝給str。實驗2 的"%3s"又多了一個條件:只拷貝3個字符。實驗3的「%[a-z]」的條件稍微嚴格一些,輸入的東西不可是字符,還得是一個小寫字母的字符,因此實驗 3只拷貝了小寫字母"aaa"給str,別忘了加上null字符。

實驗4:

 sscanf( "AAAaaaBBB" , "%[^a-z]" , str) ; ---------str的值爲 "AAA\0!!!!!!"

對於全部字符,只要不是小寫字母,都知足"^a-z"正則表達式,符號^表示邏輯非。前3個字符都不是小寫字符,因此將其拷貝給str,但最後3個 字符也不是小寫字母,爲何不拷貝給str呢?這是由於當碰到不知足條件的字符後,sscanf就會中止執行,再也不掃描以後的字符。

實驗5:

sscanf( "AAAaaaBBB" , "%[A-Z]%[a-z]" , str) ; ---------段錯誤

這個實驗的本意是:先把大寫字母拷貝給str,而後把小寫字母拷貝給str,但很不幸,程序運行的時候會發生段錯誤,由於當sscanf掃描到字符 a時,違反了條件"%[A-Z]",sscanf就中止執行,再也不掃描以後的字符,因此第二個條件也就沒有任何意義,這個實驗說明:不能使用%號兩次或兩 次以上

實驗6:

sscanf( "AAAaaaBBB" , "%*[A-Z]%[a-z]" , str) ; ---------str的值爲 "aaa\0!!!!!!"

這個實驗出現了一個新的符號:%*,與%相反,%*表示過濾 知足條件的字符,在這個實驗中,%*[A-Z]過濾了全部大寫字母,而後再使用%[a-z]把以後的小寫字母拷貝給str。若是隻有%*,沒有%的 話,sscanf不會拷貝任何字符到str,這時sscanf的做用僅僅是過濾字符串。

實驗7:

 sscanf( "AAAaaaBBB" , "%[a-z]" , str) ; ---------str的值爲 "!!!!!!!!!!"

作完前面幾個實驗後,咱們都知道sscanf拷貝完成後,還會在str的後面加上一個null字符,但若是沒有一個字符知足條件,sscanf不會 在str的後面加null字符,str的值依然是10個驚歎號。這個實驗也說明了,若是不使用%*過濾掉前面不須要的字符,你永遠別想取得中間的字符。


實驗8:

 sscanf( "AAAaaaBC=" , "%*[A-Z]%*[a-z]%[^a-z=]" , str) ; ---------str的值爲 "BC\0!!!!!!!"

這是一個綜合實驗,但這個實驗的目的不是幫咱們複習前面所學的知識,而是展現兩個值得注意的地方:

注意1:%只能使用一次,但%*可使用屢次,好比在這個實驗裏面,先用%*[A-Z]過濾大寫字母,而後用%*[a-z]過濾小寫字母。

注意2:^後面能夠帶多個條件,且這些條件都受^的做用,好比^a-z=表示^a-z且^=(既不是小寫字母,也不是等於號)。

實驗9:

int k;

sscanf( "AAA123BBB456" , "%*[^0-9]%i" , &k) ; ---------k的值爲123

首先,%*[^0-9]過濾前面非數字的字符,而後用%i把數字字符轉換成int型的整數,拷貝到變量k,注意參數必須使用k的地址。


本文來自CSDN博客,出處:http://blog.csdn.net/kenby/archive/2009/04/05/4051018.aspx

第二篇:

今天翻google reader的時候看到這樣一篇文章,介紹的是sscanf的高級用法。直到今天我才知道sscanf是能夠直接用正則表達式的,慚愧。

在msdn中sscanf的聲明以下

int sscanf( const char *buffer, const char *format [, argument ] ... );

雙字節版本的是這樣的

int swscanf( const wchar_t *buffer, const wchar_t *format [, argument ] ... );

第一個參數是源字符串,這沒什麼好講。第三個及之後的參數是可變參數列表,用於接收解析出來以後的值,可變參數列表不是本文的重點,暫且不提。最有 玄機的是第二個參數,也就是所謂的format。咱們知道prinft,sprintf,scanf,sscanf這四個函數(以及相應的雙字節版本)都 接收一個名爲format的字符串做爲參數,以便對輸入輸出作格式化,好比

sscanf(「12」, "%d", &in)

能夠把字符串"12"(唸作一二)格式化成10進制數12(唸作十二),並賦值給in,而

    sscanf(「12」, "%s", str)

C語言手冊,那麼你必定對次很是熟悉,並喜歡在中間夾雜點啊三啊啥的組成諸如%.4ld之類的format贏取初學者(或者老闆)的讚賞。可是你可真不必定了解,format裏是能夠直接用正則表達式的,好比

sscanf("123334abcd123", "%[0-9]*", str);

執行完後str的內容是字符串"123334"。[0-9]*是一個很是簡單的正則表達式,意思是匹配數字任意次。關於正則表達式的更多內容請參看這個。

咱們在寫程序時常常會碰到須要解析字符串的狀況,而正則表達式則是解決此類問題的利器。若是咱們能善用c標準庫函數就能使用的正則表達式,必定能夠作到事半而功倍。

------------

附正則表達式完整列表

字元

描述

\

將下一個字元標記為一個特殊字元、或一個原義字元、或一個向後引用、或一個八進位轉義符。例如,「n」匹配字元「n」。「\n」匹配一個換行符。序列「\\」匹配「\」而「\(」則匹配「(」。

^

匹配輸入字元串的開始位置。若是設置了RegExp對象的Multiline屬性,^也匹配「\n」或「\r」之後的位置。

$

匹配輸入字元串的結束位置。若是設置了RegExp對象的Multiline屬性,$也匹配「\n」或「\r」以前的位置。

*

匹配前面的子表達式零次或屢次。例如,zo*能匹配「z」以及「zoo」。*等價於{0,}。

+

匹配前面的子表達式一次或屢次。例如,「zo+」能匹配「zo」以及「zoo」,但不能匹配「z」。+等價於{1,}。

?

匹配前面的子表達式零次或一次。例如,「do(es)?」能夠匹配「do」或「does」中的「do」。?等價於{0,1}。

{n}

n是一個非負整數。匹配確定的n次。例如,「o{2}」不能匹配「Bob」中的「o」,可是能匹配「food」中的兩個o。

{n,}

n是一個非負整數。至少匹配n次。例如,「o{2,}」不能匹配「Bob」中的「o」,但能匹配「foooood」中的全部o。「o{1,}」等價於「o+」。「o{0,}」則等價於「o*」。

{n,m}

mn均為非負整數,其中n<=m。最少匹配n次且最多匹配m次。例如,「o{1,3}」將匹配「fooooood」中的前三個o。「o{0,1}」等價於「o?」。請注意在逗號和兩個數之間不能有空格。

?

當該字元緊跟在任何一個其餘限制符(*,+,?,{n},{n,},{n,m})後面時,匹配模式是非貪婪的。非貪婪模式盡可能少的匹配所搜索的字元串,而默認的貪婪模式則盡可能多的匹配所搜索的字元串。例如,對於字元串「oooo」,「o+?」將匹配單個「o」,而「o+」將匹配全部「o」。

.

匹配除「\n」以外的任何單個字元。要匹配包括「\n」在內的任何字元,請使用像「[.\n]」的模式。

(pattern)

匹配pattern並獲取這一匹配。所獲取的匹配能夠從產生的Matches集合獲得,在VBScript中使用SubMatches集合,在JScript中則使用$0…$9屬性。要匹配圓括號字元,請使用「」或「」。

(?:pattern)

匹配pattern但不獲取匹配結果,也就是說這是一個非獲取匹配,不進行存儲供以後使用。這在使用「或」字元(|)來組合一個模式的各個部分是頗有用。例如,「industr(?:y|ies)就是一個比」industry|industries'更簡略的表達式。

(?=pattern)

正向預查,在任何匹配pattern的字元串開始處匹配查找字元串。這是一個非獲取匹配,也就是說,該匹配不須要獲取供以後使用。例如, 「Windows(?=95|98|NT|2000)」能匹配「Windows2000」中的「Windows」,但不能匹配「Windows3.1」中 的「Windows」。預查不消耗字元,也就是說,在一個匹配發生後,在最後一次匹配之後當即開始下一次匹配的搜索,而不是從包含預查的字元之後開始。

(?!pattern)

負向預查,在任何不匹配pattern的字元串開始處匹配查找字元串。這是一個非獲取匹配,也就是說,該匹配不須要獲取供以後使用。例如 「Windows(?!95|98|NT|2000)」能匹配「Windows3.1」中的「Windows」,但不能匹配「Windows2000」中 的「Windows」。預查不消耗字元,也就是說,在一個匹配發生後,在最後一次匹配之後當即開始下一次匹配的搜索,而不是從包含預查的字元之後開始

x|y

匹配x或y。例如,「z|food」能匹配「z」或「food」。「(z|f)ood」則匹配「zood」或「food」。

[xyz]

字符集合。匹配所包含的任意一個字元。例如,「[abc]」能夠匹配「plain」中的「a」。

[^xyz]

負值字符集合。匹配未包含的任意字元。例如,「[^abc]」能夠匹配「plain」中的「p」。

[a-z]

字元範圍。匹配指定範圍內的任意字元。例如,「[a-z]」能夠匹配「a」到「z」範圍內的任意小寫字母字元。

[^a-z]

負值字元範圍。匹配任何不在指定範圍內的任意字元。例如,「[^a-z]」能夠匹配任何不在「a」到「z」範圍內的任意字元。

\b

匹配一個單詞邊界,也就是指單詞和空格間的位置。例如,「er\b」能夠匹配「never」中的「er」,但不能匹配「verb」中的「er」。

\B

匹配非單詞邊界。「er\B」能匹配「verb」中的「er」,但不能匹配「never」中的「er」。

\cx

匹配由x指明的控制字元。例如,\cM匹配一個Control-M或回車符。x的值必須為A-Z或a-z之一。否則,將c視為一個原義的「c」字元。

\d

匹配一個數字字元。等價於[0-9]。

\D

匹配一個非數字字元。等價於[^0-9]。

\f

匹配一個換頁符。等價於\x0c和\cL。

\n

匹配一個換行符。等價於\x0a和\cJ。

\r

匹配一個回車符。等價於\x0d和\cM。

\s

匹配任何空白字元,包括空格、製表符、換頁符等等。等價於[\f\n\r\t\v]。

\S

匹配任何非空白字元。等價於[^\f\n\r\t\v]。

\t

匹配一個製表符。等價於\x09和\cI。

\v

匹配一個垂直製表符。等價於\x0b和\cK。

\w

匹配包括下劃線的任何單詞字元。等價於「[A-Za-z0-9_]」。

\W

匹配任何非單詞字元。等價於「[^A-Za-z0-9_]」。

\xn

匹配n,其中n為十六進位轉義值。十六進位轉義值必須為確定的兩個數字長。例如,「\x41」匹配「A」。「\x041」則等價於「\x04」&「1」。正則表達式中可使用ASCII編碼。.

\num

匹配num,其中num是一個正整數。對所獲取的匹配的引用。例如,「(.)\1」匹配兩個連續的相同字元。

\n

標識一個八進位轉義值或一個向後引用。若是\n以前至少n個獲取的子表達式,則n為向後引用。否則,若是n為八進位數字(0-7),則n為一個八進位轉義值。

\nm

標識一個八進位轉義值或一個向後引用。若是\nm以前至少有nm個獲得子表達式,則nm為向後引用。若是\nm以前至少有n個獲取,則n為一個後跟文字m的向後引用。若是前面的條件都不滿足,若nm均為八進位數字(0-7),則\nm將匹配八進位轉義值nm

\nml

若是n為八進位數字(0-3),且m和l均為八進位數字(0-7),則匹配八進位轉義值nml。

\un

匹配n,其中n是一個用四個十六進位數字表示的Unicode字元。例如,\u00A9匹配版權符號(©)。

相關文章
相關標籤/搜索