C++Builder Programming Forum
C++Builder  |  Delphi  |  FireMonkey  |  C/C++  |  Free Pascal  |  Firebird
볼랜드포럼 BorlandForum
 경고! 게시물 작성자의 사전 허락없는 메일주소 추출행위 절대 금지
C++빌더 포럼
Q & A
FAQ
팁&트릭
강좌/문서
자료실
컴포넌트/라이브러리
메신저 프로젝트
볼랜드포럼 홈
헤드라인 뉴스
IT 뉴스
공지사항
자유게시판
해피 브레이크
공동 프로젝트
구인/구직
회원 장터
건의사항
운영진 게시판
회원 메뉴
북마크
볼랜드포럼 광고 모집

C++빌더 팁&트릭
C++Builder Programming Tip&Tricks
[684] [String] 문자열 검색 및 문자열관련함수 - 펌+
장성호 [nasilso] 14186 읽음    2007-07-23 15:38
[펌+]는 퍼온것에서 수정하여 개선하거나 ,추가또는 변환한것 등을 의미합니다.


[개요]
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]
맨날 펌질만 하고 스스로의 내공에서 나오는것이  없네요 쩝쩝~~!
장성호 [nasilso]   2007-07-24 08:34 X
  [속도문제 개선]
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;
김태선 [cppbuilder]   2007-07-24 09:14 X
좋은 자료입니다.
소스를 볼수 있으면 만드는 것도 금방입니다.
이미 내공이 많이 쌓이고 계신거죠.

+ -

관련 글 리스트
684 [String] 문자열 검색 및 문자열관련함수 - 펌+ 장성호 14186 2007/07/23
Google
Copyright © 1999-2015, borlandforum.com. All right reserved.