Sybase ASE 문자열의 UTF-8 바이트수 , 글자수 구하는 함수
Sybase ASE DBMS에서 UTF-8 바이트수 , 글자수 구하는 함수에 대해 살펴본다. Sybase ASE Non-Unicode 인코딩인 EUC-KSC에서 Unicode 인코딩인 UTF-8로 변환하는 프로젝트에서 만들어서 사용했던 함수이다.
* UTF-8 인코딩 참고: UTF-8 – 위키백과, 우리 모두의 백과사전 (wikipedia.org)
EUC-KSC에서 varchar(10)으로 선언된 컬럼을 UTF-8로 변환시 최대 바이트수와 글자수를 확인할 필요가 있는데, 기본으로 제공하는 함수가 없어서 직접 만들어서 사용했다.
UTF-8로 변환시 최대 바이트수와 글자수는 문자열 컬럼의 최대 길이를 얼마로 선언해야 할지 판단하는데 필요하다. 선언된 길이가 아닌 EUC-KSC 인코딩으로 저장된 값에 대해 UTF-8 인코딩으로 변환한 바이트수와 글자수를 계산하여 최대값을 구하는데 이 함수를 사용했다.
DBMS는 Sybase ASE v15.5 에서 테스트했다. 다른 버전에서는 테스트하지 않았으나 잘 동작할 것이라고 본다.
Sybase ASE는 MS-SQL과 매우 유사하여 MS-SQL에서도 별다른 수정없이 그대로 사용할 수 있을 것이다.
1. UTF-8 바이트수 구하기 함수
IF OBJECT_ID('dbo.GET_UTF8_BYTE') IS NOT NULL DROP FUNCTION dbo.GET_UTF8_BYTE GO CREATE FUNCTION dbo.GET_UTF8_BYTE ( @IN_VAL VARCHAR(4000) ) RETURNS INT AS BEGIN DECLARE @CHK_LENGTH INT, @I INT, @CHK_BYTE INT, @BYTE_LEN INT, @UTF8_BYTE_LEN INT, @SUM_UTF8_BYTE_LEN INT SELECT @I = 1, @CHK_LENGTH = LEN(@IN_VAL), @SUM_UTF8_BYTE_LEN = 0 WHILE @I <= @CHK_LENGTH BEGIN SELECT @CHK_BYTE = ASCII(SUBSTRING(@IN_VAL, @I, 1)) IF @CHK_BYTE >= 128 -- ASCII 코드가 alpha, numeric, control 문자 범위를 넘는 경우(2 Byte 문자일 경우) SELECT @BYTE_LEN = 2, @UTF8_BYTE_LEN = 3 ELSE SELECT @BYTE_LEN = 1, @UTF8_BYTE_LEN = 1 SELECT @SUM_UTF8_BYTE_LEN = @SUM_UTF8_BYTE_LEN + @UTF8_BYTE_LEN, @I = @I + @BYTE_LEN END RETURN @SUM_UTF8_BYTE_LEN END GO
이 코드는 다음과 같은 사실에 기반하여 작성하였다.
- Non-Unicode 1 Byte의 ASCII 코드가 128 이상이면 2바이트 문자(한,중,일 등)
- Non-Unicode 한글 1글자(2바이트)는 UTF-8 인코딩에서 3바이트로 저장됨
주요 코드에 대한 설명은 다음과 같다.
- 18행: 입력 문자열을 한 바이트씩 읽는다.
- 21행: 읽은 바이트의 ASCII 코드가 128 이상인 경우 건너뛸 바이트 길이를 2로 설정, UTF-8 바이트 수를 3 증가
- 23행: 읽은 바이트의 ASCII 코드가 128 미만인 경우 건너뛸 바이트 길이를 1로 설정, UTF-8 바이트 수를 1 증가
- 25행: UTF-8 바이트 수 합계 누적, WHILE 반복문의 조건 변수 @I 값을 건너뛸 바이트 길이 만큼 증가
2. UTF-8 글자수 구하기 함수
위 함수를 다음과 같이 변형하면 UTF-8 바이트 수가 아닌 글자수를 얻을 수 있다.
IF OBJECT_ID('dbo.GET_CHAR_CNT') IS NOT NULL DROP FUNCTION dbo.GET_CHAR_CNT GO CREATE FUNCTION dbo.GET_CHAR_CNT ( @IN_VAL VARCHAR(4000) ) RETURNS INT AS BEGIN DECLARE @CHK_LENGTH INT, @I INT, @CHK_BYTE INT, @BYTE_LEN INT, @UTF8_BYTE_LEN INT, @SUM_UTF8_BYTE_LEN INT, @SUM_CHAR_CNT INT SELECT @I = 1, @CHK_LENGTH = LEN(@IN_VAL), @SUM_UTF8_BYTE_LEN = 0, @SUM_CHAR_CNT = 0 WHILE @I <= @CHK_LENGTH BEGIN SELECT @CHK_BYTE = ASCII(SUBSTRING(@IN_VAL, @I, 1)) IF @CHK_BYTE >= 128 -- ASCII 코드가 alpha, numeric, control 문자 범위를 넘는 경우(2 Byte 문자일 경우) SELECT @BYTE_LEN = 2, @UTF8_BYTE_LEN = 3 ELSE SELECT @BYTE_LEN = 1, @UTF8_BYTE_LEN = 1 SELECT @SUM_UTF8_BYTE_LEN = @SUM_UTF8_BYTE_LEN + @UTF8_BYTE_LEN, @I = @I + @BYTE_LEN SELECT @SUM_CHAR_CNT = @SUM_CHAR_CNT + 1 END --RETURN @SUM_UTF8_BYTE_LEN RETURN @SUM_CHAR_CNT END
16행부터 시작하는 WHILE 반복문은 @I 변수를 조건으로 종료한다. @BYTE_LEN 변수는 읽은 바이트의 ASCII 코드에 따라 2(2 바이트 문자) 또는 1(1 바이트 문자)로 설정되고 25행에서 @I에 더해진다. 이 로직으로 WHILE 반복문은 문자개수만큼 반복 실행된다.
26행에서 @SUM_CHAR_CNT는 1씩 증가시키는 이유는 반복횟수가 문자개수이기 때문이다.