1.問題の原因
C言語プログラミングを使用して、テキストファイルAndroid.logで文字列を検索し、「CameraService :: connect」と「logicalCameraId:5、cameraId:5」を検索して、文字列を含む行を出力します。
文字列検索は、特にログ内の特定の情報の場所が重要な役割を果たす場合によく発生する問題です。大量のテキストデータで必要な情報を見つける方法には、検索アルゴリズムの速度と精度に対する高い要件があります。
2.アルゴリズムの選択
文字列検索アルゴリズムには、KMPアルゴリズム、通常のマッチング、ブルートフォース検索、Rabin-Karpアルゴリズム、Sundayアルゴリズム、BFアルゴリズムなど多くの種類があります。
各文字列検索アルゴリズムリファレンスWebサイトの原理の詳細な説明と実装:リンク
この記事では、BF(最も基本的な文字列照合アルゴリズムであるBrute-Force)の改良版である線形時間計算量文字列照合アルゴリズムであるKMP(Knut Morris Pratt)アルゴリズムを使用します。kmpアルゴリズムは、主に文字列検索プロセス中のバックオフを減らし、未使用の操作を可能な限り減らすことを目的としています。アルゴリズムの複雑さはO(n + m)です。
KMPアルゴリズムの全体的な考え方は何ですか?一連の例を見てみましょう。
KMPアルゴリズムとBFアルゴリズムの「開始」は同じです。同じことは、メイン文字列とパターン文字列の最初の桁を揃え、文字ごとに左から右に比較することです。
最初のラウンドでは、パターン文字列がメイン文字列の最初の同じ長さの部分文字列と比較され、最初の5文字が一致し、6番目の文字が一致しないことがわかります。これは「不良文字」です。
現時点で、一致したプレフィックス「GTGTG」を効果的に使用するにはどうすればよいですか?
プレフィックス「GTGTG」では、最後の3文字の「GTG」と最初の3文字の「GTG」が同じであることがわかります。
次の比較ラウンドでは、これら2つの同一のフラグメントを整列させることによってのみ一致することができます。これらの2つの文字列フラグメントは、それぞれ最長一致接尾辞部分文字列および最長一致接頭辞部分文字列と呼ばれます。
2番目のラウンドでは、パターン文字列を2つの位置に直接戻し、2つの「GTG」を位置合わせして、メイン文字列の不良文字Aから比較を続けます。
明らかに、メイン文字列の文字Aはまだ不良文字であり、この時点で一致するプレフィックスはGTGに短縮されています。
最初の考え方に従って、最長一致の接尾辞部分文字列と最長一致の接頭辞部分文字列を再定義します。
第3ラウンドでは、パターン文字列を再び2桁戻し、2つの「G」を揃えて、メイン文字列の不良文字Aとの比較を続けます。
上記はKMPアルゴリズムの全体的な考え方です:一致するプレフィックスの中で最長の一致するサフィックスサブストリングと最長の一致するプレフィックスサブストリングが見つかり、次のラウンドで2つが直接整列されて、パターン文字列。
記事のリンクを引用する:リンク
三、プログラムの実現
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int KMP(char s[],char t[]);
void Getnext(int next[],char t[]);
int main(int argc, char *argv[])
{
//Read the file
FILE *fp = fopen("/root/program/Android.log","r");
if(fp == NULL)
{
printf("Open error!");
return 0;
}
//Read the string that the user wants to look up.
printf("Please enter the number of strings of you want to find: \n");
int x ;
scanf("%d",&x);
char str[x][100];
for (int i = 0; i < x; i ++)
{
printf("Please enter a string: \n");
scanf("%s",&str[i]);
}
//Assigns the read to s and outouts it
char s[1000];
int m = 1; //row
while(fgets(s,sizeof(s),fp))
{
//char t[] = "CameraService::connect";
for (int i = 0; i < x; i ++)
{
int n = 0; //column
n = KMP(s,str[i]);
if (n != -1)
{
printf("%s is in the %d row %d column \n",str[i],m,n);
printf("%s \n",s);
}
}
m++; //row +1
}
fclose(fp); //close file
return 0;
}
/*
KMP算法
关键在于next,回退位置
*/
int KMP(char s[],char t[])
{
int i=0,j=0;
int slen = strlen(s);
int tlen = strlen(t);
int next[tlen]; //next数组长度与字符串t等长?
Getnext(next,t);
while(i < slen && j < tlen)
{
if(j == -1 || s[i] == t[j])
{
i++;
j++;
}
else
{
j = next[j]; // j回退
}
}
if (j == tlen)
return i - j; //匹配成功,返回子串位置
else
return (-1); //匹配失败
}
void Getnext(int next[],char t[])
{
int j = 0,k = -1;
next[0] = -1;
int tlen =strlen(t);
while(j < tlen -1)
{
if (k == -1 || t[j] == t[k])
{
j++;
k++;
if(t[j] == t[k]) //当两个字符相同时,就跳过
next[j] = next[k];
else
next[j] = k;
}
else
{
k = next[k];
}
}
}