[펌+]는 퍼온것에서 수정하여 개선하거나 ,추가또는 변환한것 등을 의미합니다.
[개요]
AnsiString의 Pos 함수는 문자열에서 찾고자 하는 문자열이 있는 위치를 반환합니다.
그런데 문자열안에 검색문자열이 여러개 있는경우에 SubString으로 찾은 위치까지 짤라서 반복합니다.
아래와 같은식이죠
void __fastcall TForm1::Button5Click(TObject *Sender)
{
String str=RichEdit1->Text;
String substr=Edit1->Text;
int p;
int cnt=0;
int len=substr.Length();
p=str.Pos(substr);
while(p>0)
{
cnt++;
str=str.SubString(p+len,str.Length()-p-len);
p=str.Pos(substr);
}
ShowMessage(cnt);
}
//---------------------------------------------------------------------------
int __fastcall GetNumberOfSubstr2(const String substr,String str)
{
int p;
int len=substr.Length();
p=str.Pos(substr);
int cnt=0;
while(p>0)
{
cnt++;
str=str.SubString(p+len,str.Length()-p-len);
p=str.Pos(substr);
}
return cnt;
}
//------------------------------------------------------------------------
[AnsiStrPos를 이용한 문자열검색]
그런데 "SysUtils.hpp"에 보면 AnsiPos 이외에 AnsiStrPos 라는 함수가 있습니다.
extern PACKAGE int __fastcall AnsiPos(const AnsiString Substr, const AnsiString S);
extern PACKAGE char * __fastcall AnsiStrPos(char * Str, char * SubStr);
보시면 아시겠지만 파라메타가 AnsiString이 아닌 char *형입니다.
AnsiStrPos 이 함수를 이용하여 문자열 검색을 구현하면
SubString으로 짤라붙이기를 하지 않고 가능하다.
char * __fastcall AnsiStrPosEx(char *Str,char *SubStr, Cardinal InitPos)
{
char *result = NULL;
if( InitPos > StrLen(Str))return NULL;
result = AnsiStrPos(Str+InitPos,SubStr); // InitPos 만큼 char *를 증가시켜서 AnsiStrPos를 사용
return result;
}
//---------------------------------------------------------------------------
int __fastcall AnsiPosEx(const String Substr,String S, Cardinal InitPos)
{
char *ret;
ret = AnsiStrPosEx(S.c_str(),Substr.c_str(),InitPos-1);
if( ret == NULL)return 0;
else return ret-S.c_str()+1; //위치 pos를 찾는 코드..
}
//---------------------------------------------------------------------------
int __fastcall AnsiPosEx2(const String Substr,String S, Cardinal InitPos) //AnsiStrPosEx를 쓰지 않고
{
if( (InitPos-1) > S.Length())return 0;
char *ret;
ret = AnsiStrPos(S.c_str()+InitPos-1,Substr.c_str());//,InitPos-1);
if( ret == NULL)return 0;
else return ret-S.c_str()+1; //위치 pos를 찾는 코드..
}
int __fastcall GetNumberOfSubstr(const String Substr,String S)
{
int result = 0;
int len = Substr.Length();
int p=1-len; //맨처음엔 1 , 그다음부턴 position + SubString의 Length
while(p=AnsiPosEx(Substr,S, p+len))result++;
return result;
}
//---------------------------------------------------------------------------
//type
//TStrPosArr = array of integer;
int __fastcall EnumSubstr(const String Substr,String S,int *&spa)
{
int result = 0;
int isize=10;
spa=(int *)malloc(10*4);
int len=Substr.Length();
int p = AnsiPosEx(Substr,S,1);
while(p)
{
if( result >= isize )
{
isize+=10;
spa=(int *)realloc(spa,isize*4);
}
spa[result] = p;
result++;
p = AnsiPosEx(Substr,S,p+len);
}
return result;
}
//---------------------------------------------------------------------------
[사용예]
void __fastcall TForm1::Button1Click(TObject *Sender) //예1
{
Label1->Caption = Format("%d 개",ARRAYOFCONST(( (int) GetNumberOfSubstr(Edit1->Text,RichEdit1->Text) )) );
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender) //예2
{
int* spa;
int ret,i;
ret = EnumSubstr(Edit1->Text,RichEdit1->Text,spa);
Label1->Caption = Format("%d 개",ARRAYOFCONST(( (int) ret )) );
RichEdit1->SelStart = 0;
RichEdit1->SelLength = RichEdit1->Text.Length()-1;
RichEdit1->SelAttributes->Color = clBlack;
if( ret > 0)
{
for( i = 0 ;i< ret;i++ )
{
RichEdit1->SelStart = spa[i]-1;
RichEdit1->SelLength = Edit1->Text.Length();
RichEdit1->SelAttributes->Color = clRed;
}
}
free(spa);
}
//---------------------------------------------------------------------------
[문제점]
* SubString으로 짤라서 처리하는것보다 오히려 속도가 2~2.5배 느리다. - 왜그럴까? ( 모름)
[원본 ]
http://blog.livedoor.jp/junki560/archives/16392117.html
[궁금한점]
원본소스에 보면 EnumSubstr에서 int *& 대신 TStrPosArr 라고 int형 배열(array of integer ) 을 선언해서 사용한다.
CBuilder에서 하려면 어떻게 하는 몰라서.... 위와같이 코딩하였다.
//type
//TStrPosArr = array of integer;
누가좀 갈켜줘요
[P.S]
맨날 펌질만 하고 스스로의 내공에서 나오는것이 없네요 쩝쩝~~!
AnsiStrPos 대신 api의 strstr을 쓰니 훨씬 빨라졌다.
SubString을 이용한 GetNumberOfSubstr2 함수보다 좀더 ...
1만회를 돌리면서 여러번 테스트 결과 약 20%정도 빠른것 같다
int __fastcall AnsiPosEx3(const String Substr,String S, Cardinal InitPos)
{
if( (InitPos-1) > S.Length())return 0;
char *ret;
ret = strstr(S.c_str()+InitPos-1,Substr.c_str());
if( ret == NULL)return 0;
else return ret-S.c_str()+1;
}