수업 시작에 앞서...
데이터를 처리하기 위해서 인코딩 방식에 대해서 익숙해 질 필요가 있다.
인코딩과 디코딩에 간단하게 말하자면 다음과 같다. 인코딩과 디코딩은 서로 반대되는 처리이다.
인코딩(encoding) : 부호화. 한 문자를 쪼개서 코드화. 한글 처리에 주의해야한다.
디코딩(decoding) : 복호화. 1과 0의 코드들를 합쳐서 문자화.
아래에서 설명하지만, 자바는 UTF-16을 사용하고 웹에서는 UTF-8을 사용하기 때문에 경우에 따라 CharacterSet을 변환해야 하는 상황이 발생할 수 있다.
UTF-8 형식으로 JSP 를 작성할 때에는 파일도 UTF-8 형식으로 저장해야 한다.
캐릭터 셋(CharacterSet)
사람이 사용하는 문자를 컴퓨터가 이해할 수 있도록 문자에 각 코드값을 부여한 것이다.
유니코드(unicode)
국제 표준으로 제정된 2바이트계의 만국 공통의 국제 문자부호 체계(UCS : Universal Code System)를 말한다.
애플컴퓨터, IBM, 마이크로소프트 등이 컨소시엄으로 설립한 유니코드(Unicode)가 1990년에 첫 버전을 발표하였고, ISO/IEC JTC1 에서 1995년 9월 국제표준으로 제정하였다. 공식 명칭은 ISO/IEC 10646-1(Universal Multiple-Octet Coded Character Set)이다.
데이터의 교환을 원활하게 하기 위해 문자 1개에 부여되는 값을 16비트로 통일하였다.
코드의 1문자 당 영어는 7비트, 비영어는 8비트, 한글이나 일본어는 16비트의 값을 가지게 되는데 이들을 모두 16비트로 통일한 것이다.
UTF-8 과 UTF-16
UTF-8 과 UTF-16 의 차이를 한 마디로 말하면 문자를 표현할 때의 단위가 다르다는 것이다.
UTF-8 은 8비트 가변장 멀티바이트에서 문자를 표현하고 UTF-16 은 16비트 가변장 멀티바이트에서 문자를 표현한다.
① UTF-8 (8Bit UCS Transformation Format)
웹에서 기본적으로 사용하는 코드. UCS-2로 정의되는 문자 집합을 이용하여 기술된 문자열을 바이트 열로 변환하는 방식의 1개 1문자를 1~6바이트 가변장 멀티바이트로 변환한다.
② UTF-16 (16Bit UCS Transformation Format)
자바의 기본 코드. 자바에서는 문자 하나를 저장하기위한 바이트 수는 영문자이든, 한글문자이든 구분없이 2바이트(16비트)를 차지하게 된다.
UCS-2 (Universal Multiple-Octet Coded Character-2)로 정의되는 문자 집합을 이용하여 기술된 문자열에 UCS-4의 일부 문자를 채워넣기 위한 인코딩 방식. UTF-8과 병용할 수 있다. UCS-2로 이용할 수 있는 문자수를 대폭 늘릴 수 있다.
※ 자바 단에서는 UTF-16을 사용하고 웹에서는 UTF-8을 사용하기 때문에 경우에 따라 변환해야 하는 상황이 발생할 수 있다.
문자 코드의 종류
KSC5601
한글 완성형 표준(한글 2,350자 표현).
한국공업표준 정보처리분야(C)의 5601번 표준안.
KSC5636
영문자에 대한 표준.
한국공업표준 정보처리분야(C)의 5636번 표준안. 기존 ASCII Code 에서 역슬래시(\)를 원(₩) 표시로 대체.
EUC-KR (MS949)
Bell-Laboratories 에서 유닉스 상에서 영문자 이외의 문자를 지원하기 위해 제안한 확장 유니코드(Extend UNIX Code) 중 한글 인코딩 방식.
영문은 KSC5636으로 처리하고, 한글은 KSC5601로 처리. 즉, EUC-KR(MS949) = KSC5636 + KSC5601
UTF-8
영문과 숫자는 1바이트, 한글은 3바이트로 표현.
(웹에서 많이 사용. UTF-8 형식으로 JSP 를 작성할 때에는 파일도 UTF-8 형식으로 저장해야 한다.)
UTF-16
자바 기본 문자 코드. 영문과 숫자는 1바이트, 한글은 2바이트로 표현.
ISO-8859-1
서유럽 언어 표기에 필요한 US-ASCII 에 없는 94개의 글자의 순차적 나열.
CharacterSet 예제 코드 - CharacterSet 의 변환 메소드, 예외 처리 맛보기 관찰
예제 코드에 앞서...
이번 코드에서는 예외의 처리에 대해서 다루고 있다. 포스팅 자바 19 (2020.08.28) 에서 예외처리에 대해 자세히 다룰 예정이지만 당장 아래의 코드를 관찰하는데 필요한 정보를 간단히 살펴보자.
* 예외(Exception) 관련 사항
- UnsupportedEncodingException 예외 : 지원되지 않는 문자 인코딩에 대해 발생하는 예외이다. 종종 사용해왔던 IOException 과 마찬가지로 『import java.io.UnsupportedEncodingException;』 구문을 작성해준다.
- 예외 던지기 (throws) : IOException 예외를 사용해오면서, 지금까지는 메소드 내에서 예외(Exception)가 발생하면 메소드 밖으로 던져줘왔다.(메소드 선언부에 『throws IOException』 을 명시 → 메소드 내에서 IOException 예외가 발생하면 메소드 실행을 중단하고 예외를 메소드 밖으로 -해당 메소드를 호출한 곳으로- 던진다. 실행 중이던 메소드는 강제종료)
- 예외 처리 (try-catch) : 예외의 발생이 예상되는 영역을 try{ } 블럭으로 감싸서 예외 발생을 감시한다. 예외가 발생하면 처리할 내용을 catch{ } 블럭에 작성하여 예외를 처리한다. 이렇게 예외를 처리하면 메소드 밖으로 예외를 던질(throws) 필요가 없다.
※ character set 변환 관련 메소드
메소드 | 설명 |
static String System.getProperty(String key) |
System 클래스의 getProperty(String key) 메소드는 현재 사용하고 있는 운영체제의 시스템 속성(property) 정보 중 인자로 전달받은 key 에 해당하는 값을 얻어온다. ex) System.getProperty("file.encoding"); // MS949 - 사용하고 있는 운영체제가 어떤 문자 코드로 file을 인코딩하는지 확인한다. |
byte[] getBytes() | String 클래스의 getBytes() 메소드는 메소드를 호출한 String 객체의 문자열을 byte 배열로 반환한다. 단, 매개변수가 없는 getBytes() 는 현재 시스템의 default character set 을 기반으로 한다. ex) "김소소".getBytes().length; // == 6 // MS949 기반의 한글은 2 byte |
byte[] getBytes(String charset) | String 클래스의 getBytes() 메소드의 오버로딩으로, charset 종류 이름을 String 으로 전달하면 해당 문자 코드 기반의 byte 배열을 반환한다. ex) "김소소".getBytes("utf-8").length; // == 9 // UTF-8 기반의 한글은 3 byte |
String(byte[] bytes, String charset) | String 클래스의 생성자 중 하나로, 첫 번째 매개변수인 byte 배열을 String 으로 생성하되 두 번째 매개변수의 인코딩 방식으로 지정해준다. ex) byte[] buf = "김소소".getBytes(); // MS949 기반의 byte 배열 String str = new String(buf, "utf-8"); // MS949 기반 byte 배열 → UTF-8 기반으로 문자열 생성 |
★ byte 배열(EUC-KR) 은 String(EUC-KR) 으로, byte 배열(UTF-8) 은 String(UTF-8) 로 변환해야 한다.
간혹 byte 배열(EUC-KR) 을 String(UTF-8) 로 변환하려는 시도를 하게 되는데 이렇게 코딩하면 문자열이 깨지고 복구할 수 없게 된다.
ex) String convert = new String(name.getBytes("euc-kr"), "utf-8");
위 구문에 의해 바이트 배열이 깨져서 EUC-KR, UTF-8 등 어떠한 바이트 배열로 읽어와도 문자가 깨져있는 것을 확인할 수 있다. 이미 깨져서 생성된 String 객체의 byte 배열은 어떤 방식으로도 복구가 불가능하다.
/*=====================================
■■■ 자바의 주요(중요)클래스 ■■■
- 문자열 관련 클래스
- 캐릭터 셋(CharacterSet)
=====================================*/
import java.io.UnsupportedEncodingException;
public class Test146
{
// try-catch로 예외를 처리하므로 throws 할 필요 없다.
public static void main(String[] args) // throws UnsupportedEncodingException
{
byte[] buf;
String name = new String("김소소");
// ○ System.getProperty("file.encoding")
// 사용하고 있는 운영체제가 어떤 문자 코드로 file을 인코딩하는지 확인한다.
System.out.println("디폴트 캐릭터셋 : " + System.getProperty("file.encoding"));
//--==>> 디폴트 캐릭터셋 : MS949 // (EUC-KR)
// ○ String객체.getBytes()
// : String 문자열을 바이트 배열로 반환 (디폴트 캐릭터 셋 기반)
buf = name.getBytes(); // String → byte[]
System.out.println("Length : " + buf.length); // byte[] 길이 출력
//--==>> Length : 6
// EUC-KR(MS949) 기반의 한글 "김소소" 은 6 byte 이다. → 한글 2 byte
// "김소소" 을 담은 default character set 기반의 byte[] 을 한 byte 씩 출력
for( byte b : buf)
System.out.print("[" + b + "] ");
System.out.println();
//--==>> [-79] [-24] [-68] [-46] [-68] [-46]
// ↑ "김소소" 문자열을 default character set 기반으로 문자 코드 관찰
////////////////////////////////////////////////////////////////////////////////////
// ↓ "김소소" 문자열을 UTF-8 기반으로 문자 코드 관찰
try // 예외를 throws 하지 않고 try-catch 방식으로 처리한다. (throws 작성 Ⅹ)
{
// ○ String객체.getBytes("utf-8")
// String 문자열을 바이트 배열로 반환 (UTF-8 기반)
buf = name.getBytes("utf-8");
// 시스템에서 만약 "utf-8"이라는 인코딩를 지원하지 않는다면 예외가 발생할 수 있다.
// java.io.UnsupportedEncodingException;
System.out.println("Length : " + buf.length); // byte[] 길이 출력
//--==>> Length : 9
// UTF-8 기반의 한글 "김소소" 은 9 byte 이다. → 한글 3 byte
// "김소소" 을 담은 UTF-8 기반의 byte[] 을 한 byte 씩 출력
for(byte b : buf)
System.out.print("[" + b + "] ");
System.out.println();
//--==>> [-22] [-71] [-128] [-20] [-122] [-116] [-20] [-122] [-116]
////////////////////////////////////////////////////////////////////////////////////
// ↓ UTF-8 바이트 배열(buf) → UTF-8 문자열로 조립
// ○ String(byte[] bytes, Charset charset) 생성자
// 문자열을 생성하면서 인코딩 방식을 UTF-8 로 지정해준다.
//new String(buf, "utf-8");
System.out.println("Value1 : " + new String(buf, "utf-8"));
//--==>> Value1 : 김소소 // 정상적인 문자열
System.out.println();
////////////////////////////////////////////////////////////////////////////////////
// ↓ UTF-8 바이트 배열(buf) → EUC-KR(MS949) 문자열로 조립 (잘못된 변환이다.)
// ○ String(byte[] bytes) 생성자
// 시스템이 사용하고 있는 default character set 방식으로 문자열을 생성한다.
//new String(buf); // == new String(buf, MS949); // 현재 MS949 기반
System.out.println("Value2 : " + new String(buf));
//--==>> Value2 : 源??냼?냼 // 비정상적인 문자열
// ★ 현재 default charset 이 MS949 이므로
// UTF-8 기반의 byte 배열을 String 으로 변환하려면
// 정상적인 인코딩을 위해 String 생성자에 "utf-8" 을 전달해야 한다.
System.out.println();
////////////////////////////////////////////////////////////////////////////////////
// ↓ EUC-KR 문자열 → EUC-KR 바이트 배열 → UTF-8 문자열로 조립 (잘못된 변환)
String convert = new String(name.getBytes("euc-kr"), "utf-8");
System.out.println("Value3 : " + convert);
//--==>> Value3 : ???? // 비정상적인 문자열
// 비정상적인 문자열 → EUC-KR 기반 byte 배열로 반환
buf = convert.getBytes();
System.out.println("Length : " + buf.length);
//--==>> Length : 4 // 출처를 알 수 없는 바이트 크기를 반환하고 있다.
// 비정상적인 문자열 → UTF-8 기반 byte 배열로 반환
buf = convert.getBytes("utf-8");
System.out.println("Length : " + buf.length);
//--==>> Length : 11 // 출처를 알 수 없는 바이트 크기를 반환하고 있다.
/*
※ check~!!!
EUC-KR(MS949) 을 UTF-8 로 변환하겠다는 의도로 위와 같이 코딩을 해버리면
(→ 『String convert = new String(name.getBytes("euc-kr"), "utf-8");』)
위 구문에 의해 바이트 배열이 깨져서 EUC-KR, UTF-8 등
어떠한 바이트 배열로 읽어와도 문자가 깨져있는 것을 확인할 수 있다.
이미 깨져서 생성된 String 객체의 byte 배열은 어떤 방식으로도 복구가 불가능하다.
★ byte 배열(EUC-KR) 은 String(EUC-KR) 으로,
String(UTF-8) → byte 배열(UTF-8) 로 변환해야 한다.
*/
} // try 블럭 end
// try 에서 UnsupportedEncodingException 발생하면 잡아내어(catch) 예외를 처리한다.
catch (UnsupportedEncodingException e)
{
System.out.println(e.toString());
// 예외에 대한 출력을 하는 것으로 예외를 처리해버리겠다는 의미.
}
} // main() end
}
'자바 풀스택 과정 수업 정리 > 자바' 카테고리의 다른 글
자바 18-1 (2020.08.27) : 자바의 주요(중요) 클래스 - StringBuffer, StringTokenizer (0) | 2020.09.13 |
---|---|
자바 17-3 (2020.08.26) : 자바의 주요(중요) 클래스 - String (0) | 2020.09.11 |
자바 17-2 (2020.08.26) : 자바의 주요(중요) 클래스 - Wrapper (0) | 2020.09.07 |
자바 17-1 (2020.08.26) : package, import, Object, 자바의 주요(중요) 클래스 - Object (0) | 2020.09.06 |
자바 16-3 (2020.08.25) : 중첩클래스(중첩 내부클래스, 내부클래스, 로컬클래스, 익명클래스) (0) | 2020.09.06 |
최근댓글