[Perl] 정규식으로 문자열 찾기

#!/usr/bin/perl -w

open(F, "cl.txt");

@strings = <F>;

sub getIssue
{
    foreach $line (@strings) {
        $lihttps://ko.perlmaven.com/matching-numbers-using-perl-regexne =~ s/^\s+//;
        $line =~ s/\s+$//;
        if ($line =~ /\[[I|i][S|s][S|s][U|u][E|e]\s*[#]*\]\s*([A-Za-z0-9_.\-]+)/) {
        $desc = $1;
        
        return $desc;
    }

    $desc;
};

$issue = &getIssue();

close(F);

.* 가 모든 문자.

참고 : https://ko.perlmaven.com/matching-numbers-using-perl-regex

[Algorithm] KMP algorithm

String match algorithm인 KMP algorithm은 text에서 뛰어넘을 수 있는 만큼 뛰어넘으면서 string이 match되는지 확인한다. 여기서 얼마나 뛰어넘을 수 있는지에 대한 정보를 얻기 위해 Failure function이라는 함수를 이용한다.

Failure function은 찾으려는 string의 각 위치마다 공통인 prefix와 suffix의 최대 길이를 찾아 저장해둔다. 예를 들면, “ababa” 는  { 0, 0, 1, 2, 3 } 과 같이 저장한다. 구현 시에는 -1 해서 저장한다. 예에서의 값은 { -1, -1, 0, 1, 2 } 이 된다.

void get_failure_function(char str[], int len, int failure[])
{
	int i;

	failure[0] = -1;

	for (i = 1; i < len; i++) {
		int f = failure[i - 1];

		while (1) {
			if (str[i] == str[f + 1]) {
				failure[i] = f + 1;
				break;
			}
			if (f <= -1) {
				failure[i] = -1;
				break;
			}
			f = failure[f];
		}
	}
}

 

찾을 때는, 위에서 계산한 값을 이용해 string을 찾는 도중에 틀리면 바로 이전까지 맞았던 부분의 failure function value를 찾아 이전까지 같은 부분을 건너뛰고 다음 부분부터 비교한다. 예를 들어, 위의 string을 찾으려고 할 때, text가 “ababcababa” 라면, string의 처음부터 비교하다가 5번째에서 틀리면, 4번째까지는 맞으므로, 4번째의 failure function value를 찾으면 2이다. 이는 앞의 2글자는 맞다는 말이므로, text에서 4-2 만큼을 건너뛴 후, string의 3번째부터 다시 비교한다. string의 3번째도 틀리므로, 2번째의 failure function value를 찾으면 0인데, 이는 0만큼 맞다는 말(=하나도 안맞다는 말)이므로 text를 2-0 만큼 건너뛴 후, string의 1번째와 다시 비교한다. string의 첫번째와 다르면  1만큼만 이동하고, 다시 1번째와 비교한다. 맞았을 때도 맞은 부분만큼을 이용해서 건너뛴다(5번째에서 맞았으므로, 3글자가 맞고, 5-3만큼 이동한 후, 4번째부터 비교).

아래 구현은 match되는 개수를 return하도록 하였다.

int get_matched_count(char text[], int text_len, char string[], int str_len, int failure[])
{
	int count = 0;
	int t = 0;
	int s = 0;

	while (t < text_len - str_len + 1) {
		while (s < str_len) {
			if (text[t + s] != string[s])
				break;
			s++;
		}

		if (s == str_len) {
			// MATCH!
			count++;
		}

		if (s < 1) {
			t++;
			s = 0;
		} else {
			t += s - 1 - failure[s - 1];
			s = failure[s - 1] + 1;
		}
	}

	return count;
}

 

앞 부분과 공통 부분이 없는 string인 경우, 더 빨리 건너뛴다. 예를 들면, “abababababc” 에서 “ababc”({ 0, 0, 1, 2, 0 })를 찾는 경우, 5번째에서 틀리면, 앞에서부터 0글자가 같으므로, 4-0만큼 이동한 후, 1번째부터 다시 비교한다.

위 두 구현 함수의 사용 부분은 다음과 같이 될 것이다.

		int T, S;
		int count;
		int *failure_function = NULL;

		char *text = "ababcababababababababa";
		char *string = "ababa";

		T = strlen(text);
		S = strlen(string);

		failure_function = (int *)malloc(sizeof(int) * S);
		// skip the check of the memory allocation

		get_failure_function(string, S, failure_function);

		count = get_matched_count(text, T, string, S, failure_function);

		printf("%d matched\n", count);

 

[Linux:Kernel] string 처리 개선

String copying

ssize_t strscpy(char *dest, const char *src, size_t count);

ssize_t strscpy_truncate(char *dest, const char *src, size_t count);

strscpy()는 src에서 dest로 최대 count bytes를 copy한다. source string이 count bytes보다 긴 경우를 제외하고는 copy된 bytes 수를 리턴한다. 긴 경우는 -E2BIG을 리턴한다. 다른 차이는 overflow 나는 경우는 src를 truncate하는게 아니라 dest가 empty string이 된다. 에러 체크를 항상 하면 괜찮은데, 안하는 경우, truncate된 string이 문제를 일으키는 일이 많기 때문에 이렇게 동작한다고 한다.

truncate된 string이 필요한 경우는 아래 버전을 사용하면 된다. 리턴 값은 같지만, null-terminate된 truncate된 string이 dest에 들어간다.

Integer parsing

simple_strto*() 함수가 많이 사용되지만, checkpatch가 불평하듯, kstrto*()가 더 낫다. 그런데, simple_strto*()는 “123abc”와 같은 string을 123으로 변환하는데, 이게 편리한 경우도 있다. 그래서 새로운 함수가 제안되었다.

int parse_integer(const char *s, unsigned int base, <type> *val);

사실, parse_integer()는 함수가 아니라 val의 타입에 맞는 여러가지 매크로이다. val이 unsigned short라면, 디코딩은 unsigned를 기초로 하고, 결과값이 short의 범위를 벗어나지 않는지 확인된다.

최종 결과는 val안에 담기고, 디코딩된 char 수가 리턴된다. 전체 string이 decode됐는지는 s[return_value] 가 null byte인지를 체크하면 된다. null-terminate string이면 원래 s[strlen(s)]는 ‘\0’일 테니까. 아니라면, 그 곳에 parsing하는 string이 계속 있을 거다. base가 문서화되지 않은 값 PARSE_INTEGER_NEWLINE과 or되면, 맨 마지막의 newline character는 무시-sysfs file로의 input을 parsing할 때 유용하다-된다. 아무 character도 convert되지 않으면, -EINVAL을 리턴한다. overflow인 경우 -ERANGE를 리턴한다.

출처: Improving kernel string handling(http://lwn.net/Articles/643376/)

구글의 Python Tutorial

[번역] 구글의 파이썬 튜토리얼 요약.
원문은 Google’s Python Class(https://developers.google.com/edu/python/)

* Python 환경 설정

나올 때 윈도우에서는 Ctrl-Z, 다른 OS에서는 Ctrl-D

* Introduction

if __name__ == ‘__main__’:
    main()

sys.argv[0]는 프로그램 이름, sys.argv[1]은 첫번째 인자, sys.argv[2]는 두번째 인자…

TAB 문자 대신 Space들을 입력.

help(len) : len 함수에 대한 문서를 출력
dir(sys): sys 모듈에 대한 전반적인 문서
help(sys.exit): sys 내의 exit() 함수에 대한 문서

* Strings

파이썬 스트링은 “immutable”하다. 즉, 생성 후에 값을 변경할 수 없다. 따라서 다른 값이 되면 새로운 스트링이 생성된다.

“”” 로 여러줄 string 가능

[ ]로 문자 접근 가능
Slice로 substring 얻기
len(string) 은 string의 길이. sequence 타입에는 다 사용 가능
‘+’ 로 concatenate.

Value를 string 으로 변경하고 싶을 때는 str() 함수를 사용

pi = 3.14
text = ‘The value of pi is ‘ + str(pi)

정수로 나눗셈을 할 때는 // 를 사용. 6 // 5 == 1

print 뒤에 줄바꿈을 하고 싶지 않으면 마지막에 , 를 붙인다.
r 을 앞에 붙이면 ‘raw’ string. \ 를 특별히 취급하지 않는다. r’x\nx’ 는 ‘x\nx’ 가 됨. u 를 앞에 붙이면 unicode.

s.lower(), s.upper(): 소문자, 대문자로
s.strip(): 앞 뒤의 whitespace 제거
s.isalpha() / s.isdigit() / s.isspace(): 알파벳인지, 숫자인지, space인지
s.startswith(‘other’), s.endswith(‘other’): s 스트링이 다른 특정 스트링으로 시작하거나 끝나는지.
s.find(‘other’): s 스트링 안의 다른 스트링을 찾는다. 찾으면 인덱스 리턴, 못찾으면 -1
s.replace(‘old’, ‘new’): 모든 ‘old’를 ‘new’로 변경한 string 리턴
s.split(‘delim’): 주어진 delimiter로 자른 substring 리스트를 리턴,
s.join(list): split()의 반대, s를 delimiter로 리스트를 합친다.

길이가 1인 string 에 ==, <= 등의 작업을 할 수 있다. char 타입이 따로 없다.

H  e  l  l  o
0  1  2  3  4
-5 -4 -3 -2 -1

s[1:4]는 ‘ell’, s[1:]는 ‘ello’, s[:]는 ‘Hello’의 복사본, s[1:100]은 ‘ello’ – 더 큰 index를 사용하면 string의 length나 마찬가지가 된다.
s[-1]은 ‘o’, s[-4]은 ‘e’, s[:-3]은 ‘He’, s[-3:]은 ‘llo’
s[:n] + s[n:] == s 는 항상 참. n이 음수거나, index영역을 벗어났을 때도 성립.

% 연산자를 사용해 printf 같은 format string. %d는 int, %s는 string, %f/%g는 float, 오른쪽에 튜플.

text = “%d little pigs come out or I’ll %s and %s and %s” % (3, ‘huff’, ‘puff’, ‘blow down’)

너무 길면 전체 expression을 괄호로 싸면 된다.

text = (“%d little pigs come out or I’ll %s and %s and %s” %
    (3, ‘huff’, ‘puff’, ‘blow down’))

unistring.encode()와 unicode로 encoding 변환.

s = unistring.encode(‘utf-8’)
t = unicode(s, ‘utf-8’)
t == unistring

if / elif/ else. “zero” 값들(None, 0, “”, ”, [], {}, False)은 false, True/False로 boolean 값, and, or, not 사용. ()로 expression 을 감싸지 않는다.

* Lists

= 을 사용하면 그냥 reference.
‘+’ 를 사용해 list를 합칠 수 있다.

for와 in 으로 iteration

squares = [1, 4, 9, 16]
sum = 0
for num in squares:
    sum += num
print sum ## 30

in 은 독립적으로 어떤 원소가 list(또는 다른 collection)에 있는지 테스트 할 수 있다.

list = [‘larry’, ‘curly’, ‘moe’]
if ‘curly’ in list:
    print ‘yay’

range(n)은 0, 1, 2, …, n-1 까지의 숫자를 리턴. range(a, b) 는 a, a+1, a+2, …, b-1 까지를 리턴.

for i in range(100):
    print i

xrange()는 전체 리스트를 만드는 과정을 없애 성능 상 좋다.

while

i = 0
while i < len(a):
    print a[i]
    i = i + 3

list.append(elem): 리스트를 수정하여 가장 뒤에 elem 추가. 리턴하지 않는다.
list.insert(index, elem): index에 elem을 추가. 리턴하지 않는다.
list.extend(list2): list2의 원소들을 list에 추가. 리턴하지 않는다.
list.index(elem): elem이 있으면 index 리턴, 없으면 ValueError를 발생. ValueError 없이 확인하려면 in 을 사용.
list.remove(elem): 첫번째 elem을 제거, 없으면 ValueError. 리턴하지 않는다.
list.sort(): list를 sort. 리턴하지 않는다. sorted()를 더 자주 사용.
list.reverse(): list를 역순으로 변경. 리턴하지 않는다.
list.pop(index): index의 원소를 제거하고 리턴. index를 생략하면 가장 끝의 원소를 리턴(append()와 반대)

* Sorting

sorted()를 사용. reverse=True를 전달하면 역순. Case sensitive하다.

strs = [‘aa’, ‘BB’, ‘zz’, ‘CC’]
print sorted(strs) ## [‘BB’, ‘CC’, ‘aa’, ‘zz’] 
print sorted(strs, reverse=True) ## [‘zz’, ‘aa’, ‘CC’, ‘BB’]

key로 함수를 전달하면 해당 함수를 key로 정렬. key=len, key=str.lower 하면 대소문자 동일하게 취급하여 정렬.

print sorted(strs, key=str.lower) ## [‘aa’, ‘BB’, ‘CC’, ‘zz’]

key로 custom 함수 전달 가능

def MyFn(s):
    return s[-1]
print sorted(strs, key=MyFn)

cmp=cmpFn 선택 인자를 전달할 수도 있음. 내장 함수는 cmp(a, b)로 -/0/+ 로 순서를 리턴

Tuple은 struct와 비슷한 역할. 변경 불가능, 크기가 변하지 않음. () 를 통해 만듦. 크기가 1인 튜플은 ( 1, ) 처럼 , 을 넣어 만듦.

변수 할당에 사용 가능. 반환값이 여러 값을 가진 경우도 사용 가능
(x, y, z) = (42, 13, “Hike”)
(err_string, err_code) = foo()

[ _expr_ for var in list ] 형태로 원하는 형태의 리스트 생성 가능.

fruits = [‘apple’, ‘cherry’, ‘banana’, ‘lemon’]
afruits = [ s.upper() for s in fruits if ‘a’ in s ] ## [‘APPLE’, ‘BANANA’]

* Dictionaries and Files

dict = {}
dict[‘a’] = ‘alpha’
dict[‘g’] = ‘gamma’
dict[‘o’] = ‘omega’

print dict[‘a’] ## ‘alpha’
dict[‘a’] = 6
‘a’ in dict ## True
## print dict[‘z’] ## Throws KeyError
if ‘z’ in dict: print dict[‘z’] ## KeyError를 피한다.
print dict.get(‘z’) ## None

dict.get(key, not-found) 형태로 키가 없을 경우 not-found 로 설정한 값을 리턴하도록 할 수도 있다.

dict.keys(): key 리스트
dict.values(): value 리스트
dict.items(): (key, value) 튜플의 리스트

for k, v in dict.items(): print k, ‘>’, v

iterkeys(), itervalues(), iteritems()는 전체 리스트를 만들지 않아 성능 상 좋다.

hash = {}
hash[‘word’] = ‘garfield’
hash[‘count’] = 42
s = ‘I want %(count)d copies of %(word)s’ % hash # ‘I want 42 copies of garfield’

del 로 변수, list 원소, dict key/value를 지울 수 있다.

Files open(), close(). open 시 ‘rU’를 사용하면 줄바꿈을 ‘\n’으로 변형하여 준다.

f = open(‘foo.txt’,’rU’)
for line in f: ## 파일을 한 줄씩 방문
    print line, ## line 끝에 이미 줄바꿈이 포함되어 있으므로 print가 줄바꿈하지 않도록 한다.
f.close()

f.readlines()는 전체를 메모리에 올리고 줄들의 list를 리턴, read()는 전체 파일을 하나의 string으로.

파일에 쓰려면, f.write(string). print를 사용하려면, print >> f, string. python 3에서는 print(string, file=f)

codes는 unicode를 읽을 때 사용 가능

import codecs
f = codecs.open(‘foo.txt’, ‘rU’, ‘utf-8’)
for line in f: # line은 unicode string이 됨.

* Regular expression

import re
str = ‘an example word:cat!!’
match = re.search(r’word:\w\w\w’, str)
if match:
    print ‘검색 성공’, match.group() ## 발견 word:cat
else
    print ‘검색 실패’

패턴 스트링은 항상 r로 시작.

a, X, 9: 있는 그대로의 문자를 매치
.: 아무 문자 하나를 매치. \n 은 제외
\w: 하나의 word에 쓰이는 문자 하나를 매치(단어가 아님). a-z, A-Z, 0-9, _ [a-zA-Z0-9_]를 매치.
\W: non-word에 쓰이는 문자 하나를 매치
\b: word와 non-word의 경계
\s: 하나의 whitespace 문자[ \n\r\t\f]를 매치
\S: whitespace 이외의 문자를 매치
\d: 숫자 [0-9]
^: 시작
$: 끝
\를 붙여 위의 것들을 그저 문자로 사용 가능

+: 왼쪽 패턴 1개 이상.
*: 왼쪽 패턴 0개 이상.
?: 왼쪽 패턴 0개 혹은 1개
+와 *는 가장 왼쪽의 것을 찾고, greedy 하다. 

r'[\w.-]+@[\w.-]+’ 로 @ 주위에 ‘.’와 ‘-‘도 매치하도록 할 수 있다. -가 구간을 매치하지 않도록 하려면 가장 마지막에 넣는다.
[] 안의 내용을 ^로 시작하면 집합을 뒤집는다. [^ab]는 ‘a’와 ‘b’를 제외한 모든 문자를 뜻한다.

패턴 안에 ( )를 넣으면 그룹으로 구분할 수 있게 해준다.

str = ‘purple alice-b@google.com monkey dishwasher’
match = re.search(r'([\w.-]+)@([\w.-]+)’, str)
if match
    print match.group() ## ‘alice-b@google.com’
    print match.group(1) ## ‘alice-b’
    print match.group(2) ## ‘google.com’

findall(): 모든 패턴에 해당하는 string 리스트를 리턴

f = open(‘text.txt’, ‘r’)
strings = re.findall(r’some pattern’, f.read())

findall 에 ( )를 넣으면 그룹에 해당하는 튜플 리스트를 만든다.

str = ‘purple alice@google.com, blah monkey bob@abc.com blah dishwasher’
tuples = re.findall(r'(\w\.-]+)@([\w\.-]+)’, str)
print tuples ## [(‘alice’, ‘google.com’), (‘bob’, ‘abc.com’)]
for tuple in tuples:
    print tuple[0] ## username
    print tuple[1] ## host

re.search(pat, str, re.IGNORECASE) 처럼 추가 옵션 가능
IGNORECASE: 대소문자 구별하지 않음
DOTALL: 마침표 . 이 newline을 매치하도록 한다. 보통은 newline을 제외한 모든것들을 매치.
MULTILINE: 여러줄로 이루어진 string에서 ^와 $가 줄의 시작과 끝을 매치하도록 한다. 보통은 ^ $는 전체 스트링의 시작과 끝을 매치한다.

정규 표현식의 확장으로 .*? 나 .+?처럼 ?를 끝에 더해서 greedy 하지 않게 변경할 수 있다.

str = ‘<b>foo</b> and <i>so on</i>’
match = re.search(r'(<.*>)’, str)
if match:
    print match.group() ##'<b>foo</b> and <i>so on</i>’
match = re.search(r'(<.*?>)’, str)
if match:
    print match.group() ## ‘<b>’

re.sub(pat, replacement, str) 은 str에서 pat과 매치되는 모든 스트링들을 찾아 replacement로 치환한다. replacement 스트링은 \1, \2 를 이용하여 group(1), group(2)를 표현할 수 있다.

str = ‘purple alice@google.com, blah monkey bob@abc.com blah dishwasher’
print re.sub(r'([\w\.-]+)@([\w\.-]+)’, r’\1@yo-yo-dyne.com’, str)
# purple alice@yo-yo-dyne.com, blah monkey bob@yo-yo-dyne.com blah dishwasher

* Utilities

os 모듈
filenames = os.listdir(dir): dir에 있는 .과 ..을 제외한 파일이름들의 리스트, 절대경로가 아님.
os.path.join(dir, filename): filename과 dir을 합쳐서 path를 만든다.
os.path.abspath(path): path를 받아서 절대 경로를 리턴
os.path.dirname(path), os.path.basename(path): dir/foo/bar.html을 받아서 dirname ‘dir/foo’와 basename’bar.html’을 리턴
os.path.exists(path): path 가 존재하면 True를 리턴
os.mkdir(dir_path): dir 하나를 만든다.
os.makedirs(dir_path): dir_path를 만들기 위한 모든 디렉토리들을 만든다.
shutil.copy(source-path, dest-path): 파일을 복사한다. 복사될 디렉토리가 존재해야 한다.

commands 모듈: 외부 명령을 실행하고 결과물을 얻어옴.
(status, output) = commands.getstatusoutput(cmd): cmd를 실행하고 exit할 때까지 기다려서,
status int값과 output text를 tuple로 리턴한다. stdout과 stderr이 하나의 출력물로 합쳐져서 나타난다.
output = commands.getoutput(cmd): 위와 동일, status값을 받지 않는다는 것만 다름.
commands.getstatus() 라는 함수는 사용하지 말아라.
sub-process에 대한 더 많은 제어권을 원하면 “popen2” 모듈을 보라.
os.system(cmd): cmd의 결과물을 여러분 코드의 output으로 출력하고, error 코드를 리턴.

try/except. ‘except IOError, e:’ 의 형태로 exception 객체에 대한 포인터를 얻을 수 있다.

try:
  f = open(filename, ‘rU’)
  text = f.read()
  f.close()
except IOError:
  sys.stderr.write(‘problem reading:’ + filename)

urllib 모듈: url을 마치 file처럼 읽을 수 있게 한다. urlparse 모듈은 url을 분해하거나 합치는 기능을 제공
ufile = urllib.urlopen(url): url에 대한 file 같은 객체를 리턴
text = ufile.read(): 파일처럼 읽음. readlines()도 사용 가능
info = ufile.info(): 요청에 대한 meta 정보를 리턴. info.gettype() 으로 ‘text/html’ 같은 mime 타입을 얻어 옴.
baseurl = ufile.geturl(): 요청에 대한 “base” url을 얻어옴. redirect로 인해 open할 때 사용한 url과 다를 수 있다.
urllib.urlretrieve(url, filename): url의 데이터를 다운받아 filename의 file로 저장한다.
urlparse.urljoin(baseurl, url): full url을 만든다.

def wget2(url):
  try:
    ufile.urllib.urlopen(url)
    if ufile.info().gettype() == ‘text/html’:
      print ufile.read()
  except IOError:
    prit ‘problem reading url:’, url

[Linux:Kernel] strncpy 대신 strlcpy

이 글에 있는 모든 코드는 GPL License를 따릅니다(All code attached is released under the GPL License in this article).

strncpy 에서는 source의 길이가 destination의 버퍼 길이와 같거나 더 길 경우, NUL-terminate되지 않는다. 구현이 다음과 같기 때문이다.

/**
 * strncpy – Copy a length-limited, %NUL-terminated string
 * @dest: Where to copy the string to
 * @src: Where to copy the string from
 * @count: The maximum number of bytes to copy
 *
 * The result is not %NUL-terminated if the source exceeds
 * @count bytes.
 *
 * In the case where the length of @src is less than  that  of
 * count, the remainder of @dest will be padded with %NUL.
 *
 */
char *strncpy(char *dest, const char *src, size_t count)
{
        char *tmp = dest;
        while (count) {
                if ((*tmp = *src) != 0)
                        src++;
                tmp++;
                count–;
        }
        return dest;
}

그래서 NUL-terminate를 보장하기 위한 함수가 있다 strlcpy 이다. 이 함수는 size-1 만큼의 string 복사와 함께 NULL로 끝남을 보장해 준다.

/**
 * strlcpy – Copy a %NUL terminated string into a sized buffer
 * @dest: Where to copy the string to
 * @src: Where to copy the string from
 * @size: size of destination buffer
 *
 * Compatible with *BSD: the result is always a valid
 * NUL-terminated string that fits in the buffer (unless,
 * of course, the buffer size is zero). It does not pad
 * out the result like strncpy() does.
 */
size_t strlcpy(char *dest, const char *src, size_t size)
{
        size_t ret = strlen(src);
        if (size) {
                size_t len = (ret >= size) ? size – 1 : ret;
                memcpy(dest, src, len);
                dest[len] = ‘\0’;
        }
        return ret;
}

strncpy를 strlcpy로 교체해야 할 것 같지만, 현재 커널에서는 둘 다 많이 사용되고 있다.
커널에서의 두 함수의 구현은 lib/string.c 에 있다.

참고 : http://lwn.net/Articles/33812/

[Linux] Shell script 에서 문자열 다루기

참고에 매우 자세히 잘 정리되어 있다. 감사.

문자열 길이 구하기
${#string}

문자열 추출
${string:position}
${string:position:length}

문자열 조각 삭제
${string#substring}
 string의 앞에서부터 가장 짧게 일치하는 substring 제거
${string##substring}
 string의 앞에서부터 가장 길게 일치하는 substring 제거

${string%substring}
 string의 뒤에서부터 가장 짧게 일치하는 substring 제거
${string%%substring}
 string의 뒤에서부터 가장 길게 일치하는 substring 제거

참고 : 
http://wonylog.tistory.com/192

Unicode string를 MBCS string으로 바꾸는 방법

1. WideCharToMultiByte() API를 호출하는 방법
2. CRT 함수 wcstombs() 를 호출하는 방법
3. CString 생성자나 assign을 통한 방법(MFC만 가능)
4. ATL string 변환 매크로를 이용하는 방법

WideCharToMultiByte

// Assuming we already have a Unicode string wszSomeString…
char szANSIString [MAX_PATH];

    WideCharToMultiByte ( CP_ACP,                // ANSI code page
                          WC_COMPOSITECHECK,     // Check for accented characters
                          wszSomeString,         // Source Unicode string
                          -1,                    // -1 means string is zero-terminated
                          szANSIString,          // Destination char string
                          sizeof(szANSIString),  // Size of buffer
                          NULL,                  // No default character
                          NULL );                // Don’t care about this flag

wcstombs

    wcstombs ( szANSIString, wszSomeString, sizeof(szANSIString) );

CString

// Assuming we already have wszSomeString…

CString str1 ( wszSomeString );    // Convert with a constructor.
CString str2;

    str2 = wszSomeString;          // Convert with an assignment operator.

ATL Macro

#include <atlconv.h>

// Again assuming we have wszSomeString…

{
char szANSIString [MAX_PATH];
USES_CONVERSION;  // Declare local variable used by the macros.

    lstrcpy ( szANSIString, OLE2A(wszSomeString) );
}

참고 : Introduction
to COM – What It Is and How to Use It.
by Michael Dunn