이제부터 설명드릴 내용의 주제는 Chr()과 Asc()함수에 대해서인데, 유니코드 버전 함수와 어떻게 다른지
그리고 Byte계열 함수는 또 어떤 식으로 활용될 수 있는지에 대한 것입니다.
문자열을 다루는데 있어서 숙련된 분들은 "뭬이야~" 하실지도 모르겠지만,
가끔은 이런 쬐끄만 실험으로 머리를 식히시는 것도 '좋지 않을까'하는 생각이 듭니다. ^^
일단 최대한 난이도를 낮춰서 초급 수준에 맞도록 설명드리도록 노력하겠지만,
기본적인 활용에 대한 설명이 아니므로 어느 정도는 감안해주셨으면 좋겠네요.
그리고 그냥 읽으시는 것보다 '직접 실행' 창을 활용해보실 것을 권해드립니다.
이제 본론으로 들어가보겠습니다.

Chr()함수는 문자코드에 대한 문자를 반환하고 Asc()함수는 문자에 대한 문자코드를 반환하는 함수입니다.
이 함수 외에도 ChrW(), ChrB(), AscW(), AscB()함수가 있고 Chr$(), ChrW$(), ChrB$()함수도 있죠.
각 반환값의 변수형은 다음과 같습니다.

Chr(), ChrW(), ChrB() : Variant형
Chr$(), ChrW$(), ChrB$() : String형
Asc(), AscW() : Integer형
AscB() : Byte형

특이한 점은...
$가 붙은 함수는 String형의 값을, 없는 것은 Variant형을 되돌린하는 점인데,
Variant형은 어떤 형의 문자(열) 또는 값에 관계없이 기본적으로 16바이트를 소모한다는 단점이 있습니다.
(장점은, 명시적인 타입 캐스팅 없이 데이터를 자유롭게 흐르게한다는 것인데, 경우에 따라 다르지만
일반적인 어플리케이션에서는 좋지 않은 것으로 여겨집니다. 하지만 가끔은 유용하게 사용되기도 합니다.)
Chr()계 함수의 인수가 Integer형이 아닌 Long형으로 되어 있다는 점이죠.
Chr()과 Asc()는 전통적으로 사용되어오던 함수인데, 이에 비해 다른 함수들에 대해서는 도움말에
다음과 같은 참고 사항들이 붙어있습니다.
-------------------------------------------------------------------------------------
ChrB 함수는 문자열이 가지는 바이트 데이터를 사용합니다.
1바이트나 2바이트 크기의 문자를 반환하는 대신 ChrB 함수는 1바이트만 반환합니다.
ChrW 함수는 Unicode를 지원하지 않는 플랫폼을 제외한 플랫폼에서
Unicode 문자를 포함하는 String 값을 반환하고 Chr 함수와 동일한 작동을 합니다.
=====================================================================================
AscB 함수는 문자열이 가지는 바이트 데이터를 사용합니다.
AscB 함수는 문자 코드의 첫 글자를 반환하는 대신에 첫째 바이트를 반환합니다.
AscW 함수는 Unicode를 지원하지 않는 플랫폼을 제외한 플랫폼에서
Unicode 문자 코드를 반환하고 Asc 함수와 동일한 작동을 합니다.
-------------------------------------------------------------------------------------

이제부터 설명드릴 함수는 다음과 같습니다.
ChrW(), Chr(), AscW(), Asc()

평소에는 그냥 지나치곤 하는 위 함수들에 '반환값'에 대해서 이야기하려고 합니다.
실험을 위해 "가"와 "나"라는 문자를 사용할 것입니다.
먼저, "가"의 문자코드는 시스템코드로 &HB0A1, 유니코드로는 &HAC00입니다.
물론 메모리나 파일에는 little-endian이 적용되므로 &HA1, &HB0 또는 &H00, &HAC의 순서가 됩니다.
이제 이 코드를 사용하여 문자 "가"를 출력해보겠습니다.
('직접 실행'창에서 타입하는 것으로 간주합니다. MsgBox 또는 Debug.Print를 이용해볼 수도 있구요.)

Print ChrW(&HAC00)


우리가 아는 바대로 아주 당연한 결과를 출력합니다.
그럼 이건 어떨까요.

Print ChrW(&HB0A1)


우리는 B0A1역시 시스템코드로 "가"라는 것을 알기 때문에, 이럴 때 눈치없이 "낡"자를 출력하는
비베가 야박해보일 수도 있습니다. (하필이면 "낡았다"할 때의 "낡"이라는 점이... ^^;)
이렇게 '당연한' 실험을 한가지 더 해보겠습니다. 이번엔Chr()함수를 사용합니다.

Print Chr(&HB0A1)


이게 무엇이 이상하냐구 반문하시는 분들도 계시겠지만 아직 모르시는 분들도... 어쩌면... ;;
"가"라는 문자를 표현하기 위해 ChrW()함수에는 유니코드를, Chr()함수에는 시스템코드를 넣었다는 점이
비베로선 전혀 이상할 것이 없는 차이점입니다. (!)
그럼 그 반대는 어떨까요.

Print Hex(Asc("가"))
B0A1

Print Hex(AscW("가"))
AC00

역시 예상한대로, "W"가 붙은 함수는 유니코드를, 없는 함수는 시스템코드를 사용하는 것을 보실 수 있습니다.
흔히 문자열 코드를 변환하기 위해 StrConv()함수를 사용합니다.
설마하니... 시스템코드를 얻기 위해 문자열을 파일로 저장했다가 배열로 읽는다든지...
이런 일은 없으리라 믿겠습니다. (자수합니다~ ;;)

StrConv(문자열, 변환형식, LocaleID)

이 함수의 도움말에도 참고 사항이 있는데 다음과 같군요.
-------------------------------------------------------------------------------
ANSI 형식에서 Byte 배열을 문자열로 변환하려면 StrConv 함수를 사용하고
Unicode 형식에서 이런 배열을 변환하려면 대입문을 사용합니다.
-------------------------------------------------------------------------------
바로 위에서 제가 자수한 내용, 즉 파일에서 바이트형 배열로 읽어들인 문자열은 시스템코드
(여기서는 "ANSI 형식"이라고 하는군요.)로 되어 있습니다.
이것을 문자열로 넣으면... 여전히 시스템코드로 된 문자열이 들어가겠죠.

Get #hTextFile, , Buffer()
txtEdit.Text = Buffer

유니코드 텍스트파일을 읽은 경우엔 이렇게 하면 됩니다만, 시스템코드의 보통 텍스트라면
문제가 좀 다르죠. 그래서 이걸 유니코드로 변환하는 과정이 필요하구요.

txtEdit.Text = StrConv(Buffer, VbUnicode)

반대로 파일에 저장할 시스템코드로 된 배열을 만들어야 할 때는 인수로 VbFromUnicode를
사용해야 합니다.
StrConv()함수는 문자열 또는 문자를 바꾸는 일을 하지만, 굳이 이 함수를 사용하지 않아도
하나의 문자 정도라면 Asc(), Chr()을 적절하게 활용하는 것도 도움이 될 것 같습니다.

다음으로... "B", Byte계열 함수에 대해서 이야기해보겠습니다.
이제 "나"라는 문자를 사용할 차례죠. ("가"에는 상위바이트에 값 '0'이 있어서 좀...)
미베에서 "나"의 문자코드는 &HB098입니다. 그리고 ChrB()는 문자의 각 바이트를 따로 떼어놓은 것이니
다음과 같이 해볼 수 있지요.

Print ChrB(&HB0) & ChrB(&H98)
?

헉... 실험 실패인가요. -_-;;
실은 그렇지 않습니다. 우리가 다루는 문자들은 1바이트가 아닌 2바이트를 사용하고 있습니다.
그런데 어찌된 일인지 인텔계열의 프로세서들은 big-endian이 아닌 little-endian을 사용하고 있죠.
예를 들어 '&H10203040'과 같은 Long값은 메모리상에 다음과 같이 배치됩니다.
([]안 값의 단위는 16진수/1바이트입니다.)

[40] [30] [20] [10]

유니코드의 값 역시 Integer이므로 다음과 같이 해야 정상적으로 출력되겠죠.

Print ChrB(&H98) & ChrB(&HB0)


이제서야 제대로 되었군요.
그럼 AscB()는 어떨까요. 예상대로라면 아마도... &H98만 출력이 되어야 옳을 겁니다. 이제...

Print Hex(AscB("나"))
98

여기서 우리가 배운 교훈은 "가나다라"와 같은 문자열의 유니코드 아스키값은 다음과 같고,
(단위 : 16진수/2바이트)

[AC00] [B098] [B2E4] [B77C]

이것이 유니코드 문자열로 메모리나 파일에 배열될 때는 다음과 같은 순서로 된다는 점..
(단위 : 16진수/1바이트)

[00] [AC] [98] [B0] [E4] [B2] [7C] [B7]

그리고 실제로 시스템의 메모리 상이나 파일에서는 다음과 같이 배열된다는 점입니다.
(단위 상동)

[A1] [B0] [AA] [B3] [D9] [B4] [F3] [B6]

그리고 AscB()함수는 시스템코드가 아닌 유니코드의 하위 바이트를 반환합니다.
ChrB()는 문자의 각 바이트로 쪼갠 값을 나타낼 수 있고 다음과 같이 하면...

Print ChrB(&H0) & ChrB(&HAC) & ChrB(&H98) & ChrB(&HB0) & ChrB(&HE4) & _
ChrB(&HB2) & ChrB(&H7C) & ChrB(&HB7)

"가나다라"라는 문자열을 출력한다는 점입니다.
물론 ChrB()로는 시스템코드로 된 문자열도 조합해낼 수 있습니다.
다음과 같이 하면...

'시스템코드로 문자열을 조합한 후 유니코드로 변환하여 출력...
Print StrConv(ChrB(&H41) & ChrB(&HB3) & ChrB(&HAA), vbUnicode)

"A나"라는 문자열을 출력하구요.
마지막으로, 바이트형 배열이나 문자열이나 어지간하면 동족으로 통한다는 점이죠.
(ChrB()를 사용한 문자열 조합은 바이트형 배열로도 동일한 방식으로 가능합니다.)
(그러고보니 팁 게시판의 글 1103번에서도 다루고 있군요.)

이렇게해서 Chr()과 Asc()에 대한 대략적인 이야기가 끝이 났습니다.
(뒷부분이 좀 우중충하다는 점이 좀 걸립니다만... ^^;)
이 외에도 문자열을 다루는 함수에 Len(), Left(), Right(), Mid()함수 등이 있는데,
여기에도 "B"가 붙은 함수들이 존재하며 용법은 위에서 설명드린 "B"계열 함수의 원리에서
찾아보실 수 있습니다.
문자열 정보를 시스템코드 그리고 바이트 단위로 다뤄야 할 때 꼭 필요한 함수들이죠.

기회가 되신다면, 메모리 상의 문자열은 어떤 식으로 동작하는지 공부하는 것도
문자열을 보다 빠르고 효율적으로 처리하는데 도움이 될 것 같습니다.
물론 함수나 대입문의 활용법을 배우는 방법도 있습니다만, 이렇게 내부에서 일어나는 일들에 대해서
관심을 가지게 되면 보다 나은 방법을 찾는데 보탬이 되리라 믿구요.
무엇보다도... 일단 재미있으니까요.. ^^ (비베탐험~ 신비의 세계~♪)

이상... 사족전문 꽃사냥꾼의 실험실였습니다.
비베건강~*

추신: 문자열 관련 함수들은...
[F2]를 눌러 개체 찾아보기 창을 열고, 검색 콤보에 'strings'라고 기입한 후 검색하시면 됩니다.
물론 라이브러리 선택에서 VBA, 클래스에서 Strings를 선택하셔고 볼 수 있구요.
한가지 더...
텍스트파일을 읽는 방법으로 흔히 String형으로 버퍼를 만드는데, 이것은 1바이트계 문자만으로 이루어진 파일에서
유효하며 2바이트계 문자(한글, 한자, 특수문자 등)가 포함될 경우엔 바이트형 배열로 읽는 방법이 안정적입니다.
Posted by housegod
l