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

C/C++ 팁&트릭
[16] [STL]C++에서의 大小文字 변환 방법
김백일 [cedar] 11982 읽음    2002-06-20 00:56
안녕하세요? 김백일입니다.

이 팁은 Effective STL의 부록 A의 내용을 참고했습니다.
원래는 대소문자를 비교하지 않는 문자열 비교 방법에 대한 것이지만,
여기서는 대소문자 변환만 소개하겠습니다.
(더 자세한 것은... 책을 사보세요!)

-----------------------------------------------------------------------------

ANSI C에서
문자 하나를 대문자로 변환하는 함수는
ctype.h 헤더파일에 있는 toupper(), 소문자는 tolower()이고,
문자열(char 배열)의 모든 문자를 대문자로 변환하는 함수는
string.h의 strupr(), 소문자는 strlwr() 인 것은 알고 계실 겁니다.
(단, ANSI C에는 없고, 볼랜드 컴파일러에서만 가능합니다. 참고로 C++빌더/카일릭스의 vcl.h나 clx.h에 있는 StrUpper(), StrLower() 함수도 같은 역할입니다. 물론 AnsiString의 UpperCase(), LowerCase() 함수를 더 많이 사용하지요.)

그런데,
ANSI C++ string 객체는 자체적으로 대소문자 변환기능을 제공하지 않습니다.

물론, 제일 쉬운 방법은
c_str()을 써서 C 문자열로 변환한 뒤 strupr()나 strlwr()를 쓴 후,
다시 string 객체를 새로 생성하는 것입니다.

#include <cstring> // ANSI C의 string.h를 인클루드해야 합니다.

...

string s1 = "Character Classification Facilities";
string s2 = strupr(s1.c_str());

저와 같은 Only C++ 주의자에게는 상당히 맘에 안드는 방법이죠. ^^;

물론 C++만으로도 가능합니다.
ANSI C++에도 문자 하나를 대문자와 소문자로 변환하는 함수로
<locale> 헤더 파일의 toupper()와 tolower()가 있습니다.
(문자열의 경우는 조금 후에 얘기하겠습니다.)
그러므로 문자열을 toupper()와 tolower()를 써서 변환하려면
다음과 같이 transform 알고리듬을 사용하면 됩니다.

transform( s.begin(), s.end(), s.begin(), toupper );
transform( s.begin(), s.end(), s.begin(), tolower );


영어의 경우는 대소문자 변환이 상당히 쉬운 작업이라서
굳이 위와 같이 toupper와 tolower 함수를 쓰지 않고, 단순히 아스키값의 덧셈, 뺄셈을 사용해서 간단한 코딩으로 구현할 수 있습니다만,
독일어나 불어, 러시아어 같은 다른 유럽 언어들의 대소문자 변환은 그렇게 간단하지가 않습니다.

그래서 ANSI C 라이브러리의 문자열 변환 함수들은
로케일(locale)이라는 일종의 전역변수에 의해 동작이 변화합니다.
이 전역변수는 프로그래머가 직접 접근할 수는 없고요.
setlocale()이라는 함수를 써서 읽고 쓰게 되어 있습니다.

setlocale(LC_ALL, NULL)의 리턴값이 현재 지정된 로케일(기본값은 "C")이고요,
특정 언어, 예를 들어 독일어로 로케일을 변경하려면,
setlocale(LC_ALL, "de")라고 하면 됩니다.
(자세한 내용은 도움말을 참고하세요.)

그러나, 이러한 전역변수를 사용하는 방식은 구조적 프로그래밍을 위반하는
매우 좋지 않은 프로그래밍 방식이죠.
모든 ANSI C 라이브러리의 문자열 함수는 이 전역변수를 사용하므로
나중에 로케일이나 라이브러리 자체가 변경되었을 때,
코드를 재사용하지 못하게 되는 경우가 있습니다.

그래서 다양한 유럽 언어의 로케일을 고려해야하는 프로그램의 유지보수를 위해서는
ANSI C 문자열 변환 함수의 사용을 지양하는 것이 좋습니다.

또한 가장 결정적인 단점으로, 한번에 한 가지 로케일밖에는 사용하지 못합니다.
여러 언어를 동시에 다루는 다국어 프로그램은 ANSI C 라이브러리로는 작성이 불가능하다는 얘기죠.

그러므로 결론은,
역시 ANSI C++의 방식을 사용해야 한다는 겁니다.
ANSI C++ 라이브러리의 로케일은 전역변수 대신 std::locale 타입의 객체를 사용합니다.
그러므로 얼마든지 복수개의 로케일을 동시에 사용할 수 있지요.
(여기서부터는 물론, using namespace std;를 사용했다고 가정합니다.)
통상의 로케일(C 로케일)을 생성하려면
locale L = locale::classic();
으로 하면 되고,
독일어로 로케일을 생성하려면 다음과 같이 합니다.
locale L("de");
ANSI C++의 로케일의 개념은 약간 어렵습니다만
(물론 C에서도 어렵습니다만, C++은 좀 더 어렵습니다.
저도 다는 이해하지 못하고 있습니다. -_-;;)
여기서는 단순히 대소문자 변환에만 초점을 맞추겠습니다.
C++의 로케일은 각 기능별 분류에 따라 패싯(facets)이란 것으로 나누어져 있고요,
대소문자 변환과 관련된 facet은 ctype입니다.
이 ctype의 멤버함수인 ctype::toupper()나 ctype::tolower()를 사용하면 됩니다.
이 함수는 C의 toupper(), tolower()처럼 한 문자만 변환하는 함수와
(ctype::toupper, ctype::tolower가 아니라,
전역 함수인 ::toupper, ::tolower의 경우에도, 로케일에 따른 변환이 가능합니다.
두번째 인자로 로케일 객체를 넘겨주면 됩니다.)
특정 범위의 문자열을 변환하는 두 가지 함수가 오버로딩되어 있습니다.

char 배열이나 string과 같은 일반적인 문자열을 위해 ctype을 생성하는 방법은 다음과 같습니다.

#include <locale>

...

locale L; // 독일어 로케일을 쓰려면 locale L("de");
const ctype<char>& ct = use_facet<ctype<char> >(L);

이렇게 만든 ctype<char> 객체를 사용하여 대소문자 변환을 하려면 다음과 같이 합니다.

string s1 = "Character Classification Facilities";
ct.toupper(s1.begin(), s1.end());

+ -

관련 글 리스트
16 [STL]C++에서의 大小文字 변환 방법 김백일 11982 2002/06/20
Google
Copyright © 1999-2015, borlandforum.com. All right reserved.