查詢文字檔案中的關鍵字,說白了就是以文字檔案作為輸入,進行字串匹配,找返回其第一次出現的下標位置。但是由於資料是以文字檔案的形式作為輸入的,如何儲存和進行匹配就成為了乙個問題。下面以兩種方法來介紹如何操作。注:本文中採用的字串匹配演算法只是普通的字串匹配演算法,重點在對檔案處理和分塊查詢。
一、蠻力法
這種方法非常簡單,把檔案中的所有資料輸入到乙個字元陣列中,然後以陣列作為主串,關鍵字為模式串,進行字串匹配即可。
但是這裡有乙個問題,就是字元陣列要多大才合適?由於不同的檔案的資料量可能差別非常大,所以我們應該根據檔案的大小來動態分配字元陣列來儲存主串。即我們現在的問題變為如何獲得檔案的大小。檔案的大小可以用如下的方法來獲得,首先開啟文字檔案,儲存其檔案位置,然後把檔案指標定位到檔案的末尾,獲得其偏移量,然後再把檔案指標恢復到原先即可。恢復檔案指標是為了不讓該呼叫對檔案的其他操作產生影響,從外部看來這個操作呼叫前與呼叫後檔案的狀態並沒有變化過。其現實**如下,返回檔案所佔的字元總數:
[cpp]view plain
copy
?int
getfilelength(ifstream &inputfile)
則實現字串匹配的函式如下:
[cpp]view plain
copy
?int
indexinfile(
const
char
*filename,
const
char
*keyword)
//獲得檔案的長度,即位元組數,並開劈乙個同樣大小的陣列儲存檔案資料
intlength = getfilelength(inputfile);
char
*text =
newchar
[length+1];
//把檔案的內容講到陣列中
inputfile.read(text, length);
inputfile.close();
text[length] = '\0'
; //進行模式串匹配,並返回結果
intindex = indexof(text, length, keyword, strlen(keyword));
delete
text;
return
index;
} int
indexof(
const
char
*text,
inttextsize,
const
char
*match,
intmatchsize)
//匹配失敗
return
-1;
}
其**非常簡單,不再多說了。
二、分治法
注意,這裡主要是用到了把檔案分成若干大小相同的塊,並對各個塊進行字串匹配的方法來處理,並不是指字串匹配演算法使用了分治的思想。
由於檔案的資料可能非常巨大,一次性地把檔案的所有內容讀入到記憶體時,有時是不可能的,而且這樣做也沒有什麼必要,因為我們要查詢的串很可能就在檔案的前面部分,而我們卻把乙個檔案的所有內容調入到記憶體中,浪費了大量的記憶體空間,而且效率不高。所以我們應該把檔案進行分塊處理,每次從檔案中讀取一定的字元到緩衝區中,進行處理。其實現方法如下:
首先把開檔案,每次從檔案讀取指定個數的字元到buffer中,然後以buffer中的字元作為主串,關鍵字作為模式串進行字串匹配,若匹配成功把返回其下標,若匹配不成功,則把下標值累加上讀到緩衝區中字元的個數,並繼續從檔案中讀取字元到buffer中,繼續對buffer進行字串匹配,直到找到關鍵字,或檔案結束。
這個方法不用把檔案的所有內容調入記憶體中,而是每次都從記憶體讀入乙個buffer的內容,可以減少記憶體的開銷,不**件有多大都可行。然而這個方法的難點在**呢,難點就要當關鍵字在兩個緩衝區之間時該如何識別和處理。
下面說說我的想法,為了方便解說,我們假設buffer的大小為6,要查詢的關鍵字為defg,檔案的內容為abcdefghijk,我們每次從檔案中讀取5個字元到buffer中(第6個字元為'\0'),為abcde,可以看到我們要查詢的字串只有一部分在buffer中,它們被分為了兩個部分。首先我們判斷當在buffer上查詢不成功,是否是由於所有的字元都匹配,但是模式串還沒匹配完,主串卻已經到了盡頭,若是,把把之前與模式串匹配的部分字元複雜到buffer的前面,然後再從檔案中輸入資料,並放到其後面。在這個例子中,就是把de複製到buffer的前面,再從檔案中讀取資料到de後面的buffer中,讀入完畢後,buffer的資料變成defgh,然後再對其進行匹配,即可匹配成功。
其實現**如下:
[cpp]view plain
copy
?int
indexinfile(
const
char
*filename,
const
char
*keyword)
intkeysize = strlen(keyword);
//關鍵字的長度
intindex = 0;
//記錄關鍵字首次出現的位置
intlastmatch = 0;
//記錄最後一次匹配的位置
const
intbuffersize = 5;
char
buffer[buffersize + 1];
while
(!inputfile.eof())
else
} return
-1;
} int
indexof(
const
char
*text,
inttextsize,
const
char
*match,
intmatchsize,
int&lastmatch)
//匹配失敗
return
-1;
} void
writeendtobegin(
char
*text,
inttextsize,
intwritecount)
} **分析:
這裡主要解析一下indexof函式中的lastmatch引數,該引數記錄了主串中與模式串匹配的字元的個數。當indexof函式返回-1時,它尤其有用,因為它讓我們知道,在buffer中,有多少個字元已經與模式串(關鍵字)匹配了,在上面的例子中,就是de兩個字元,則其值為2,所以把buffer中最後的兩個字元複製到了其前面。
同時還要
注意,buffer的大小一定要大小模式串的長度,不然的話,buffer會因為裝不下乙個模式串而出錯。在**中為了演示而把buffer的大小定為6(5+1),但是在使用時應該把它改變成你想要的大小,通常256或512是乙個合適的值。
三、複雜度分析
兩個演算法的時間複雜度無為o(n*m),n為檔案的字元數,m為關鍵字的字元數(即模式串的字元數)。空間複雜度第乙個演算法為o(n),第二個演算法為o(1),因為不**件多大,緩衝區的大小都是確定的。
ps:本人成為了csdn2013部落格之星候選人之一,如果你覺得本人寫的部落格還可以,請投我一票,支援一下我,我的投票位址是:
python 查詢文字中的關鍵字
1.查詢一行中是否有某個關鍵字 lines f.readlines for line in lines if fix in line allfix.write line n 2.查詢一行中是否有某個列表中的任何關鍵字 kws buffer overflow segfault core bugfix ...
文字檔案中的 0字元
最近讀乙個檔案的某一行後,進行域切分的時候,最乙個欄位為空。明明有字元的,於是縮小範圍進行debug。因為底層是getline寫的,所以跟蹤了一下,發現getline的讀取到 n結束作為一行的。如下read到的641,但strlen 返回的為21,所以感覺是讀取到的行中包含 0字元。通過hexdum...
python 查詢文字檔案的層次
i o系統有一系列的層次構建而成 下面是操作乙個文字檔案的例子來檢視這種層次 f open sample.txt w f sample.txt mode w encoding utf 8 f.buffer io.bufferedwriter name sample.txt f.buffer raw ...