반응형
일반적인 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"
'C++11,14 (modern C++)' 카테고리의 다른 글
Singleton pattern and std::call_once (0) | 2018.09.28 |
---|---|
rvalue reference 가 항상 유익하지 않다? (2) | 2017.04.07 |
C++ 11과 C++ 99 를 동시에 지원하기 위해서 feature를 구분할 때 유용한 팁 (0) | 2016.09.07 |
gcc와 c++ feature (0) | 2016.07.18 |
stl : map 과 array 성능비교. (2) | 2016.06.09 |