본문 바로가기

개발 Note/C++11,14 (modern C++)

String Compare (without space and special char)

반응형


일반적인 String compare 함수는 정확한 string을 비교해서 처리해야 하는 경우들이 많습니다.


그런데 간혹, 문자열이 엇비슷하면 같다고 처리하고 싶을 때도 있습니다.


예를 들면,  

1. "나 ^^ 이뽀 :)~" 와 "나 ^^;;; 이뽀~~~???" 이런 문자열들을 같은 취급 하고 싶은 경우, 

2. "이 름" 과 "이름" 과 같이 공백을 무시하고 싶은경우,


3. 마지막으로  "오늘 아침 날씨" 와 "오늘 오전 날씨" 와 같이 의미 갖는 단어들을  같은 것으로  취급하고 싶은 경우,


들 일것입니다.


3번은 단순 코드로는 해결하기 힘든 내용일 것입니다. 

'비슷한 문자열'이라는 개념을 정리하는 차원에서 써 놓은 항목입니다.



일단 순수한 코드차원에서 접근하자면, 1,2번의 경우에 대해서는 간단한 해결책이 있습니다.


특수문자나 공백을 제외하고 문자열을 비교하는 코드를 작성하여 이를 사용하면 됩니다.





#include <string>

using namespace std;



bool inline
is_ignorable_ch(unsigned char c)
{
if (c<= 0x2F) return true; // control code
/*
U+0020      20  SPACE
U+0021  !   21  EXCLAMATION MARK
U+0022  "   22  QUOTATION MARK
U+0023  #   23  NUMBER SIGN
U+0024  $   24  DOLLAR SIGN
U+0025  %   25  PERCENT SIGN
U+0026  &   26  AMPERSAND
U+0027  '   27  APOSTROPHE
U+0028  (   28  LEFT PARENTHESIS
U+0029  )   29  RIGHT PARENTHESIS
U+002A  *   2a  ASTERISK
U+002B  +   2b  PLUS SIGN
U+002C  ,   2c  COMMA
U+002D  -   2d  HYPHEN-MINUS
U+002E  .   2e  FULL STOP
U+002F  /   2f  SOLIDUS
*/  
else if(0x3A <= c && c<= 0x40) return true;
/*  
U+003A : 3a  COLON
U+003B  ;   3b  SEMICOLON
U+003C  <   3c  LESS-THAN SIGN
U+003D  =   3d  EQUALS SIGN
U+003E  >   3e  GREATER-THAN SIGN
U+003F  ?   3f  QUESTION MARK
U+0040  @   40  COMMERCIAL AT
*/

else if(0x5B <= c && c<= 0x60) return true;
/*
U+005B  [   5b  LEFT SQUARE BRACKET
U+005C  \   5c  REVERSE SOLIDUS
U+005D  ]   5d  RIGHT SQUARE BRACKET
U+005E  ^   5e  CIRCUMFLEX ACCENT
U+005F  _   5f  LOW LINE
U+0060  `   60  GRAVE ACCENT
*/
else if(0x7B <= c && c<= 0x7E) return true;
/*
U+007B  {   7b  LEFT CURLY BRACKET
U+007C  |   7c  VERTICAL LINE
U+007D  }   7d  RIGHT CURLY BRACKET
U+007E  ~   7e  TILDE
*/
return false;
}

bool
is_similar(const std::string& str1, const std::string& str2)
{
const char* s1 = str1.c_str();
const char* s2 = str2.c_str();
int l1 = str1.size();
int l2 = str2.size();

int i=0,j=0;
for( ;i<l1 && j<l2;)
{
if(is_ignorable_ch(s1[i])){i++; continue;}
if(is_ignorable_ch(s2[j])){j++; continue;}
if(s1[i] != s2[j]) return false;
i++;
j++;
}

for(i ;i<l1;i++)
if(!is_ignorable_ch(s1[i])) return false;

for(j ;j<l2;j++)
if(!is_ignorable_ch(s2[j])) return false;

return true;
}


#define TEST(P1, P2, _EXPECT) do{\
int r = is_similar(P1, P2);\
printf( "%s\t r= %s:\t %s, %s\n"\
,(r == (_EXPECT))?"PASS":"FALSE" \
,(r==true)?"true":"false"\
,#P1 \
,#P2);\
}while(0)

void compare_test()
{

int no = 0;
TEST("","", true);

TEST("", "aaa", false);


TEST("차차차... 해", "", false);

TEST("안녕하세요. ", " 안 녕 하세요, ",true);
TEST("hello... 나는 누구 ?", "hello나는누구",true);
TEST("hello... ", "he ll. o",true);
}



result 


PASS  r= true:  "", ""

PASS  r= false:  "", "aaa"

PASS  r= false:  "차차차... 해", ""

PASS  r= true:  "안녕하세요. ", " 안 녕 하세요, "

PASS  r= true:  "hello... 나는 누구 ?", "hello나는누구"

PASS  r= true:  "hello... ", "he ll. o"