블로그 이미지
잡초 개발자의 좌충우돌 이야기 yysvip

카테고리

분류 전체보기 (211)
Java Programing (24)
Web Programing (20)
Database (36)
Tool (46)
까칠한 IT (27)
까칠한 정보 (42)
까칠한 Strory (16)
까칠한 Project (0)
Total905,954
Today3,437
Yesterday7,350

달력

« » 2018.10
  1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31      

공지사항

UTF-8 문자열 자르기

  까칠한 남자 Strory       yysvip.tistory.com       잡초 개발자 까찰한 쑤의 좌충우돌 개발 이야기

 

국제화 사이트를 제작하다 보면 부딪히는 문제는 정확한 byte 수준의 문자열 조작에 있다.


테이블 생성시 varchar의 길이를 character가 아닌 byte로 주어진다던지, 아님 외부 시스템과 통합시 외부 시스템간의 통신시 제한 길이가 Byte영역에로 되어 있다던지...

 

 여러 문제로 인해서 UTF-8 문자열을 Byte영역에 길이로 자를 일이 있다. 하지만 문자열들 중 한 문자가 딱 정해진 Byte영역에를 차지한다면 문제 되지 않지만, UTF-8은 국가별로 Byte영역에 크기가 다르다.


 일반적으로 ASCII는 1Byte영역에 영역대를 쓰고 있고, 그 외 언어들은 2~3Byte영역에 코드 영역을 사용한다.

4Byte영역에는 대체 영역으로 잘 쓰이지 않는다. 즉, 국가 마다 하나의 문자가 차지하는 Byte영역에 수는 가변적인 것이다.

이를 해결하기 위해서는 String 기반에서 하나의 charater를 가져온다.
 
 자바에서 문자형은 유니코드로 되어 있다. 이를 숫자로 형변환 하면 자연스럽게 어느 Byte영역에 있는지 확인이 가능하다.

 

즉, 처음 문자부터 차곡차곡 Byte영역에 영역을 확인하여 문자열이 차지하는 Byte영역에수를 계산하여 누적하면서 누적 Byte영역에가 1024가 넘을 경우 하나의 문자열을 더희생시켜 문자열이 깨지지 않게 하는 것이다.


아래 예제 소스를 참고하기 바란다.

 

package com.tistory.yysvip.bytes;

import org.apache.log4j.Logger;


/**
 * 
 * com.tistory.yysvip.bytes
 *    |_ UTF8Cut.java
 *
 * 
* * @date : XXXX. XX. XX. * @version : * @author : YYS */ public class UTF8Cut { private Logger log = Logger.getLogger(this.getClass()); /** *
     * 1. 개요 : UTF-8 문자열 자르기
     * 2. 처리내용 : 입력받은 문자를 UTF-8 Byte 길이만큼 Byte 단위로 잘라준다
     * 
* @Method Name : cutOffUTF8String * @date : XXXX. XX. XX. * @author : 까칠한쑤 * @history : * ----------------------------------------------------------------------- * 변경일 작성자 변경내용 * ----------------------------------------------------------------------- * XXXX. XX. XX. 까칠한쑤 최초 작성 * ----------------------------------------------------------------------- * * @param str * @param maxByteSize * @param trail * @return */ public String cutOffUTF8String(String str, int maxByteSize, String trail) { try { // 널일 경우에는 그냥 리턴 if (str == null) return null; if (str.length() == 0) return str; byte strByte[] = str.getBytes("UTF-8"); if (strByte.length <= maxByteSize) return str; // 마지막 줄임말 int trailByteSize = 0; // 줄임말의 바이트 수 계산 if (trail != null) trailByteSize = trail.getBytes("UTF-8").length; // 실질적으로 포함되는 최대 바이트 수는 trailByte를 뺀 것이다. maxByteSize = maxByteSize - trailByteSize; int endPos = 0; // 마지막 바이트 위치 int currByte = 0; // 현재까지 조사한 바이트 수 for (int i = 0; i < str.length(); i++) { // 순차적으로 문자들을 가져옴. char ch = str.charAt(i); // 이 문자가 몇 바이트로 구성된 UTF-8 코드인지를 검사하여 currByte에 누적 시킨다. currByte = currByte + availibleByteNum(ch); // 현재까지 조사된 바이트가 maxSize를 넘는다면 이전 단계 까지 누적된 바이트 까지를 유효한 바이트로 간주한다. if (currByte > maxByteSize) { endPos = currByte - availibleByteNum(ch); break; } } // 원래 문자열을 바이트로 가져와서 유효한 바이트 까지 배열 복사를 한다. byte newStrByte[] = new byte[endPos]; System.arraycopy(strByte, 0, newStrByte, 0, endPos); String newStr = new String(newStrByte, "UTF-8"); log.info(newStr.getBytes("UTF-8").length + " " + newStr); newStr += trail; return newStr; } catch (Exception e) { // TODO: handle exception log.error("StringHandler cutOffUTF8String error", e); return ""; } } /** *
     * 1. 개요 : UTF-8코드 Byte를 구한다.
     * 2. 처리내용 : 문자가 몇 Byte로 구성된 UTF-8 코드인지를 검사
     * 
* @Method Name : availibleByteNum * @date : XXXX. XX. XX. * @author : 까칠한쑤 * @history : * ----------------------------------------------------------------------- * 변경일 작성자 변경내용 * ----------------------------------------------------------------------- * XXXX. XX. XX. 까칠한쑤 최초 작성 * ----------------------------------------------------------------------- * * @param c * @return */ public int availibleByteNum(char c) { // UTF-8은 최대 4바이트를 사용하고 ASCII는 1바이트 그외의 문자들은 2~3바이트 까지 조합하여 사용한다. // 즉, 어느 나라 문자이냐에 따라서 몇 바이트를 사용하는지 모르기 때문에 하나의 charater가 몇 바이트 대역에 // 있는지 조사하여 한문자의 바이트를 조사... 이를 더해 나가면 문자 단위로 몇 바이트를 차지 하는지 정확하게 조사할 수 있다. int ONE_BYTE_MIN = 0x0000; int ONE_BYTE_MAX = 0x007F; int TWO_BYTE_MIN = 0x0800; int TWO_BYTE_MAX = 0x07FF; int THREE_BYTE_MIN = 0x0800; int THREE_BYTE_MAX = 0xFFFF; int SURROGATE_MIN = 0x10000; int SURROGATE_MAX = 0x10FFFF; int digit = (int) c; if(ONE_BYTE_MIN <= digit && digit <= ONE_BYTE_MAX) return 1; else if(TWO_BYTE_MIN <= digit && digit <= TWO_BYTE_MAX) return 2; else if(THREE_BYTE_MIN <= digit && digit <= THREE_BYTE_MAX) return 3; else if(SURROGATE_MIN <= digit && digit <= SURROGATE_MAX) return 4; return -1; } public static void main(String[] args) { UTF8Cut utf8Cut = new UTF8Cut(); String str = "UTF-8 문자열 자르기 테스트"; System.out.println("=================================================="); System.out.println(str); System.out.println(utf8Cut.cutOffUTF8String(str, 10, "")); System.out.println("=================================================="); } }
Posted by yysvip

최근에 달린 댓글

최근에 받은 트랙백

글 보관함