C#에서도 쓸 수 있는 C 언어 스타일의 문자 판별식

C 언어가 사용하던 표준 함수들 (isalnum, isalpha, iscntrl, isdigit, isgraph, islower, isprint, ispunct, isspace, isupper, isxdigit)과 Visual Basic이 사용하던 Asc 함수를 기억하십니까? 모두 문자를 판별할 때에 사용하던 함수들이었습니다. 이러한 함수는 주로 Lexical Analyzer (이하 LEX)와 Yet Another Compiler Compiler (이하 YACC)와 같이 문자 판별을 중요하게 여기는 부가 도구를 비롯해서 다양한 명령어 해석기에서 사용되었습니다.

C#에서도 Lex나 Yacc를 만들 수는 없을까 하는 생각에서 저는 개인적으로 C 언어 스타일의 100% Managed Library를 제작하고 있습니다. 물론, MSDN 상의 도움말 중 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/vclrfrun-timeroutinesnetframeworkequivalents.asp 과 같은 곳을 참조해서 포팅해도 좋을 것입니다. 하지만 좀 더 간결하면서도 기존 C 언어에서 호출하던 함수와 비슷한 파라미터를 가진 “유사 함수”를 만들 수 있다면 포팅이 쉬워질거라 생각합니다.

가장 첫 단계로 문자 판별식에 대한 실험을 해보고 저는 새로운 점을 알아냈습니다. C 언어에서 쓰이던 ASCII 코드가 특별히 이상한 점 없이 잘 돌아가는 듯 보입니다. ^^ 기존 C 런타임 함수의 기능을 수행하는 C#의 동일한 한줄짜리 코드들을 보여드리겠습니다.

참고: c는 변수 또는 함수의 매개 변수로 사용하시면 됩니다. 또한 모든 판별식은 조건에 맞으면 1을, 맞지 않으면 0을 반환합니다. (C 언어 스타일의 함수들이 그러했었습니다.)


// isalnum: 영어 대문자와 소문자, 숫자를 판별하는 함수입니다.
return ((0x60 < c && 0x7b > c) || (0x40 < c && 0x5b > c) || (0x2f < c && 0x3a > c)) ? 1 : 0;

// isalpha: 영어 대문자와 소문자를 판별하는 함수입니다.
return ((0x60 < c && 0x7b > c) || (0x40 < c && 0x5b > c)) ? 1 : 0;

// isascii: ASCII 영역 내의 문자인지 판별하는 함수입니다.
return (-0x01 < c && 0x80 > c) ? 1 : 0;

// isbinary: 숫자 0 또는 1에 해당하는 문자인지 판별하는 함수입니다. (제가 추가한 함수입니다.)
return (c == 0x30 || c == 0x31) ? 1 : 0;

// iscntrl: 제어 문자를 판별하는 함수입니다.
return ((-0x01 < c && 0x20 > c) || 0x7f == c) ? 1 : 0;

// isdigit: 10진수 숫자 (0 ~ 9)에 해당하는 문자인지 판별하는 함수입니다.
return (0x2f < c && 0x3a > c) ? 1 : 0;

// isgraph: 인쇄 문자 (공백 문자 포함) 인지 판별합니다.
return ((-0x01 < c && 0x20 > c) || 0x7f == c) ? 0 : 1;

// islower: 영어 소문자인지 판별합니다.
return (0x60 < c && 0x7b > c) ? 1 : 0;

// ismbcs: 2바이트 이상의 문자인지 판별합니다. (제가 추가한 함수입니다.)
return ((0x80 < c && 0xa0 > c) || (0xdf < c && 0xfd > c)) ? 0 : 1;

// isodigit: 8진수 숫자 (0 ~ 8)에 해당하는 문자인지 판별합니다. (제가 추가한 함수입니다.)
return (0x2f < c && 0x38 > c) ? 1 : 0;

// isprint: 인쇄 가능 문자 (실제로 보이며, 읽을 수 있는 문자만 해당) 인지 판별합니다.
return ((-0x01 < c && 0x20 >= c) || 0x7f == c || (0x08 < c && 0x0e > c)) ? 0 : 1;

// ispunct: 영숫자, 공백을 제외한 기호 문자인지 판별합니다.
return ((0x1f < c && 0x30 > c) || (0x39 < c && 0x41 > c) || (0x5a < c && 0x61 > c) || (0x7a < c && 0x7f > c)) ? 1 : 0;

// issbcs: 1바이트 이내의 문자인지 판별합니다. (제가 추가한 함수입니다.)
return ((0x80 < c && 0xa0 > c) || (0xdf < c && 0xfd > c)) ? 1 : 0;

// isspace: 공백 문자인지 판별합니다.
return ((0x08 < c && 0x0e > c) || c == 0x20) ? 1 : 0;

// isupper: 영어 대문자인지 판별합니다.
return (0x40 < c && 0x5b > c) ? 1 : 0;

// isxdigit: 16진수 숫자 (0 ~ 9, A ~ E)에 해당하는 문자인지 판별합니다.
return ((0x2f < c && 0x3a > c) || (0x40 < c && 0x47 > c) || (0x60 < c && 0x67 > c)) ? 1 : 0;

문자에 관한 판별 함수는 위와 같은 식으로 축약하여 표현할 수 있음을 발견하였습니다. 위와 같은 판별식을 사용하여 System.Net.Sockets.Socket으로 주고 받는 모든 데이터 스트림에 관한 분석을 신속히 할 수도 있으며 장기적으로는 앞에서 거론하였던 Lex와 Yacc의 닷넷용 버전을 제작할 수 있는 초석이 될 거라 생각합니다. 유용하게 사용하시길 바랍니다. ^^

참고 사항: 변수 c의 형식은 byte, char, short, int, long 등 제약이 없습니다. 하지만 함수로 제작하실 때에는 int와 long에 대한 두 가지 함수만 제공하시면 충분합니다. 또한 unsigned (양수) 계열 변수는 표준 규격은 아니기에 권장하지 않습니다.

참고 서적: 영진 닷컴 표준 프로그래머 시리즈 – C 언어 함수의 사용법 + 작성법 완전 제패 (Shozo Kashihara 저)

댓글 남기기