UTF-8 String을 사용하는법

vani2의 이미지

Windows 7 Home Premium K, Debian Linux 운영체제를 실험에서 사용했습니다.

일단 유니코드, MBCS, WBCS...등등 당장 많은 문서를 보긴 했지만 정말 머리속이 하얘질정도로 복잡하네요..
그런이유로 질문이 조금 조잡하더라도 양해 부탁드리며, 질문에서 틀린점은 지적바랍니다.

아래의 질문들은 제가 C++코딩을 하면서 겪었던 문자열 인코딩 및 사용에 관한 여러 의문들입니다.

Linux나 Mac OS와 같은 유닉스 기반 운영체제에서 std::string을 사용할때 한글이나 특수문자등을 이용해 여러 작업을 하려면 어떻게 해야하나요?(그저 대입과 출력이 아닌, Parsing, Replace등의 작업을 할 수 있어야합니다)

#include <iostream>
#include <string>
 
using namespace std;
 
int main()
{
	string s{}; // C++11 Brace Initializer, '데비안리눅스'에서 실험했기 때문에 이 std::string은 UTF-8인코딩입니다
 
	s += "ㅁㄴㅇㄹ므느으르";
 
	string s2{}; // C++11 Brace Initializer
 
	s2 += s.substr(0,1); // 한글은 3byte인데 1byte만 추려내고 있습니다.
 
	cout << s2; // 정상적으로 출력되지 않습니다.
}

위 코드의 목적은 s의 "ㅁㄴㅇㄹ므느으르"라는 문자열에서 가장 첫 문자열을 s2에 저장한 후 출력하는 것인데요.

컴파일후 실행을 해보면 정상적으로 출력되지 않습니다.

컴파일은 g++로 했으며 다음과 같은 쉘을 사용했습니다.
$ g++ -std=c++11 -o test test.cpp

단. "s.substr(0,1);"부분을 "s.substr(0,3);"으로 바꾸면 문제없이 출력됩니다. 이는 UTF-8에선 한글이 3byte이기 때문입니다.

java같은 언어는 UTF-8인코딩이라고 들었는데 위의 예시와는 달리 문자열로 여러 작업을 해도 문제가 발생하지 않습니다 왜 그런건가요? 언어 자체에서 처리를 해주나요?

public class Main {
 
	public static void main(String args[])
	{
		String s = new String(); // UTF-8
 
		s = "ㅁㄴㅇㄹ";
 
		String s2 = s.substring(0, 3);
 
		System.out.println(s2); // ㅁㄴㅇ가 출력됩니다
	}
}

그리고 윈도우 운영체제에선 utf-8이 기본지원되지 않는데 제가 사용하는 IDE인 비주얼스튜디오 2013의 컴파일 옵션에 보면 "유니코드 문자 집합 사용"이라는 옵션이 있습니다. 한국어판 윈도우에선 CP949라고하는 문자열 인코딩을 사용한다고 들었는데 이 CP949가 유니코드인가요? 제 생각엔 아닌것같은데.. CP949라는 커스텀MBCS를 사용하고 유니코드를 지원하지 않으면서(이게 맞는지 모르겠습니다), 어째서 IDE에선 "유니코드 문자 집합 사용"이라는 옵션을 제공하는것인가요?(이 옵션은 무엇을 뜻하는 것인가요?)
[이미지 첨부했습니다]

그리고 위와 같은 여러 문제를 해결하기 위해 리눅스던 윈도우던 wchar_t를 사용하거나 std::wstring을 사용해서 코딩하면 문제가 해결될 수 있습니다... 하지만 저는 일반적인 std::string에 UTF-8을 사용하면서 코딩하고 싶습니다. std::wstring으로 코딩시 UCS-2, UCS-4등으로 인코딩되서 UTF-8과는달리 WideCharSet이 되어버려서 호환성이 떨어지고 용량을 더 먹는데다가 UTF-8이 필요할땐 따로 변환을 해 줘야한다고 합니다, 그리고 std::wstring을 사용하면 모든 문자열 리터럴엔 L이 붙어야하는데.. 이 와 같은 것들이 안 그래도 부족한 생산성을 저해 시키지 않을까 걱정됩니다.

위와 같은 플랫폼별 문제를 해결하고 C++에서 자바의 String처럼 유연하게 크로스플랫폼으로 UTF-8기반 문자열을 사용하는 방법이 없을까요?

다른분들은 이러한 문제를 어떻게 해결 하시고 계신지 궁금합니다.

참고로 윈도우에 종속되지 않은 크로스플랫폼을 기준으로 합니다.

File attachments: 
첨부파일 크기
Image icon image 004.png8.31 KB
익명 사용자의 이미지

Icu or qt qstring

bloody의 이미지

cp949, euc_kr 같이 특정 언어에 할당된 코드페이지는 유니코드가 아닙니다.
따라서 MBCS가 맞습니다.

윈도우즈는 내부적으로 UTF-16 LE를 기본으로 사용합니다.

제가 2013는 사용해보지 않아서 모르겠지만
IDE에서 유니코드 문자집합 사용이라는 옵션은 UNICODE/_UNICODE를 정의해주는 옵션이 아닐까 생각됩니다.
즉 해당 IDE 설정을 해놓으시면 모든 ANSI/UNICODE 옵션을 가진 컨트롤 등이나 API등이 유니코드 기본으로 되어서
유니코드만 입력하셔야 하게 될겁니다. 즉 UTF-16 LE를 사용 해주셔야 합니다.

제가 듣기론 자바, mac 등에서는 디폴트가 utf-8이 아니라 UTF-16 BE 라는 얘기를 들었습니다.
이건 확실하진 않으니 참고만 해주세요

vani2의 이미지

그렇군요.

한가지 궁금한게 있는데
그 마지막에 언급하신 Mac의 디폴트가 UTF-16 BE라는 것은 어떤것을 뜻하는 것인가요? (문자열 리터럴이 UTF-16 BE or 운영체제 기본 인코딩 or ...more)

익명 사용자의 이미지

bloody의 이미지

응용프로그램을 개발하기 위한 SDK(코코아?) 에서 UTF-16을 사용할 수 있다는 겁니다.
물론 UTF-16 유니코드를 지원한다는 뜻이지 항상 UTF-16을 써야한다는 것은 아니죠.

하지만 OS레벨에서는 항상 유니코드를 내부적으로 사용합니다. 예를들어 파일시스템에서나
폴더명이나 파일명에 아랍어나 이름 모를 생소한 언어등을 2개이상 섞어 써도 파일명이 깨져보이지
않는것은 유니코드, UTF16을 지원한다는 겁니다.

6 Software Using UTF-16

Most major software with good Unicode support uses UTF-16 (or 16-bit Unicode strings). Note that much of the software listed below runs on Unix/Linux systems as well as Windows and others.

Everything Microsoft — Windows (including Pocket PC) and applications
MacOS X and applications
Symbian (phone/mobile OS) [Symbian]
SAP [SAP]
Sybase [Sybase]
International Components for Unicode [ICU]
Rosette Core Library for Unicode [Rosette]
Modern, widespread browsers: IE, Mozilla, Opera
XML DOM 2.0 API and popular parsers (e.g. Apache Xerces)
KDE/Qt and applications
OpenOffice
Modern programming languages
Java
ECMAScript (JavaScript/JScript)
All .Net languages (C#, J#, VB.Net, etc.)
Python 1.6 (see Unicode in Python [Python])
Ada 95 [Ada95]
Enterprise Cobol [Cobol]

vani2의 이미지

그렇군요 감사합니다.

익명 사용자의 이미지

> 그리고 위와 같은 여러 문제를 해결하기 위해 리눅스던 윈도우던 wchar_t를 사용하거나 std::wstring을 사용해서 코딩하면 문제가 해결될 수 있습니다.

그리 단순하지 않습니다. 예를 들어 UTF-8로 기록된 파일을 읽어서 std::wstring에 저장해 사용하려면 저장하기 전에 변환이 필요합니다.
UTF-8은 문자 하나가 차지하는 byte가 문자마다 다르니까요. 파일로 출력할 때에도 마찬가지입니다. 그런 변환을 위한 라이브러리가 필요합니다.

> 하지만 저는 일반적인 std::string에 UTF-8을 사용하면서 코딩하고 싶습니다.

std::string은 그런 용도로 쓸 수 없습니다. 포기하세요. std::string의 메소드들은 "문자"를 "char 타입 데이터 하나"로 간주합니다.

> java같은 언어는 UTF-8인코딩이라고 들었는데

아닙니다. UTF-16을 사용합니다. 자바의 경우 char 타입이 2 byte이고 자바 String은 연속적인 char 데이터를 추상화한 타입입니다.
고로 자바 String은 UTF-8을 직접 다루지 못합니다. 위에 적은 std::wstring의 경우와 마찬가지로 변환이 필요합니다.
C++과는 달리 표준 라이브러리가 인코딩 변환 기능을 제공합니다.

> WideCharSet이 되어버려서 호환성이 떨어지고 용량을 더 먹는데다가

대신에 단순하고 빠르지요. 문자 하나가 차지하는 byte수가 고정되어 있으면, 문자열을 다루는 알고리즘이 단순해지고 결과적으로 빨라집니다.

익명 사용자의 이미지

첨언하자면, 프로그램이 UTF-8 문자열을 직접 다루는 것이 좋을 이유가 별로 없습니다.
그 프로그램이 돌아갈 환경과 사용할 데이터에 따라 달라집니다.
OS의 기본 인코딩도 사용자가 설정할 수 있으니 특정한 인코딩을 미리 가정하는 것은 좋지 않습니다.
사용할 데이터(예를 들어 텍스트 파일)가 어떤 character set으로 인코딩되어 있을지도 미리 알기 어렵구요.

익명 사용자의 이미지

> 프로그램이 UTF-8 문자열을 직접 다루는 것이 좋을 이유가 별로 없습니다.

정정합니다. "프로그램이 내부적으로 문자열을 UTF-8을 사용해서 다루는 것이 좋을 이유가 별로 없습니다."

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.