Notice
Recent Posts
Recent Comments
Link
«   2025/05   »
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
Archives
Today
Total
관리 메뉴

Everything has an expiration date

141 - Java 자바의 주요 클래스 : 캐릭터 셋(Character Set), getBytes(), new String(byte[], incoding) 본문

[Java]

141 - Java 자바의 주요 클래스 : 캐릭터 셋(Character Set), getBytes(), new String(byte[], incoding)

Jelly-fish 2023. 9. 19. 13:59
/*==============================================
  ■■■ 자바의 주요(중요) 클래스 ■■■
  - 자바에서 기본적으로 제공하는 주요 클래스들
  - 문자열 관련 클래스
  - 캐릭터 셋(CharacterSet)
================================================*/

/*
■ 캐릭터 셋(Character Set)

   ○ 유니코드(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바이트를 차지하게 된다.
		UCS-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개 글자의 순차적 나열.



*/


// 인코딩 디코딩 방식 동일해야 한다.
// 영문, 숫자는 1Byte라 다른 디코딩 방식으로 합친다 하더라도 알파벳 자체가 깨지진 않는다.
// → book → o o k
// 그러나, 한글은 하나의 바이트가 소실된다 하더라도, 완전히 깨져버린다. (뷁쉛...)
// 이미 완성되어 있는 형태에 번호를 매겨서 인코딩, 디코딩 방식으로 정했다. 
// 자음 모음 조합형이었다면 다른 인코딩, 디코딩 방식으로 해석한다 하더라도 완전히 깨질 일은 없을 것이다.

// [ ANSI = MS949 ]*********
// 한글 : 2byte
// 알파벳 : 1byte → 알파벳 대소문자는 깨질 일이 없는 이유. (동일하게 1Byte) 
// 특수문자 : 2byte
//**************************

// [ UTF-8 ] ***************
// 한글 : 3byte  
// 알파벳 : 1byte → 알파벳 대소문자는 깨질 일이 없는 이유. (동일하게 1Byte) 
// 특수문자 : 3byte
//*************************


import java.io.UnsupportedEncodingException;


public class Test141
{
	public static void main(String[] args) throws UnsupportedEncodingException
	{
		byte[] buf;
		String name = new String("오수경");

		// 파일에 대한 인코딩 방식을 확인. (getProperty() 메소드 활용)
		// System 클래스의 static 메소드 
		// (java.lang.System. 이므로 별도 호출 x, static이므로 인스턴스 생성 x)
		// 매개변수로 뭘 넘겨주느냐에 따라 인코딩 방식을 알려주는 메소드.
		System.out.println("디폴트 캐릭터셋 : " + System.getProperty("file.encoding"));
		//--==>> 디폴트 캐릭터셋 : MS949

		// String의 static 메소드
		// 『String.getBytes()』
		// : 대상문자열을 디폴트 캐릭터셋으로(시스템에 설정된 인코딩 방식을 활용해서)
		//   바이트 배열을 반환하는 메소드

		buf = name.getBytes(); //--> 수경님의 이름을, 바이트 배열로 반환. 2byte * 3 = 6byte → 배열 길이 6.
		// byte = 3bit = 2³ → (000) 1 byte

		System.out.println("Length : " + buf.length);
		//--==>> Length : 6
		
		for(byte b : buf)
			System.out.println("[" + b + "]");
		System.out.println();
		//--==>> [-65]
		//       [-64]
		//       [-68]
		//       [-10]
		//       [-80]
		//       [-26]
		// -65, -64  = "오"
		// -68, -10  = "수"
		// -80, -26  = "경"
		
		// 괄호가 비어있으면 → 디폴트 캐릭터셋으로 바이트 배열 반환
		// 괄호 안에 인코딩 방식이 있으면 → 매개변수로 넘겨받은 인코딩 방식으로 바이트 배열 반환

		// "UTF-8" 캐릭터셋으로 바이트 배열을 반환
		// 『String.getBytes("utf-8")』
		// : 대상 문자열을 매개변수로 넘겨받은 인코딩 방식을 활용해서
		//   바이트 배열을 반환하는 메소드

		buf = name.getBytes("utf-8");
		// Java : 이 인코딩 형식이 지원이 안 되면 난 어떻게 바이트 배열을 반환해...?
		// 넘긴 인코딩 방식이 시스템에서 지원을 안 하면 어떡해!
		// 지원하지 않는 인코딩 방식일 경우의 예외 처리를 설정해 줘야지!
		// → [ throws UnsupportedEncodingException ]
		//          예외 상황이 발생하면 던져!
		

		//--==>> 에러 발생(컴파일 에러)
		//       UnsupportedEncodingException
		//→ Exception 처리 후 다시 실행. 즉, 예외 처리 후... 다시 확인

		System.out.println("Length : " + buf.length);
		//--==>> Length : 9

		for(byte b : buf)
			System.out.println("[" + b + "]");
		System.out.println();
		//--==>> 
		/*
		[-20]
		[-104]  오
		[-92]

		[-20]
		[-120]  수
		[-104]
		
		[-22]
		[-78]   경
		[-67]
		*/

		// String() - 생성자
        // String 빈 문자 시퀀스를 나타내도록 새로 생성된 개체를 초기화합니다 .
        // Initializes a newly created String object so that it represents an empty character sequence.
		

		/*
		String(String original)
        Initializes a newly created String object so that
		it represents the same sequence of characters as the argument;
		in other words, the newly created string is a copy of the argument string.
		
		String(byte[] bytes, String charsetName)
        Constructs a new String by decoding the specified array
		of bytes using the specified charset.
		
		*/
		// new String("오수경"); 
		// new String(바이트 배열, 인코딩방식);
		// new String(buf, "utf-8");

		//  utf-8 형태로 저장된 바이트 배열을
		//  String 객체로 파라미터 값 『utf-8』을 부여하여 생성.
		//  → 즉, utf-8 기반으로 buf 바이트 배열을 합쳐서 문자열 객체를 생성한 후 출력.

		// "오수경" 문자열을 글자당 2byte씩 쪼개서 저장한 것을
		//  다시 합쳐서, utf-8 로 디코딩.	
		System.out.println("Value 1 : " + new String(buf, "utf-8"));
		//--==>> Value 1 : 오수경

		System.out.println();	// 개행


		/*
		String(byte[] bytes)
        Constructs a new String by decoding the specified array of bytes using the platform's default charset.
		*/

		// new String(바이트배열[, 기본인코딩방식]);
		// new String(buf);
		
		//  utf-8 형태로 저장된 바이트 배열을
		//  String 객체로 두 번째 파라미터 값 없이 부여하여 생성.
		//  → 즉, ms949 기반으로 buf 바이트 배열을 합쳐서 문자열 객체를 생성한 후 출력.
		System.out.println("Value 2 : " + new String(buf));
		//--==>> Value 2 : ?삤?닔寃?
		
		// 원래 utf-8 로 저장했던 byte 배열을 ms949로 디코딩하자 "오수경" 문자열이 완전히 깨져버렸다!


		System.out.println();	// 개행
		System.out.println("---------------------------------------------------");

		// 문자열 객체를 생성할 때부터 잘못된 형태.
		String convert = new String(name.getBytes("euc-kr"), "utf-8");

		System.out.println("Value 3 : " + convert);
		//--==>> Value 3 : ??????

		
		buf = convert.getBytes();
		System.out.println("Length : " + buf.length);
		//--==>> Length : 6


		buf = convert.getBytes("utf-8");
		System.out.println("Length : " + buf.length);
		//--==>> Length : 18

		

		// [옳은 방식] 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓
		//  
		// - ① name("오수경")을 "utf-8" 인코딩 방식으로 인코딩하고 바이트 배열로 반환.
		// - ② String(바이트 배열 buf, 디코딩방식 "utf-8")
		//      String(byte 배열, 디코딩 방식) 생성자로, 바이트 배열을 입력한 디코딩 방식으로 문자열 변환.
		//      그 문자열을 String으로 합쳐서 반환.
		//
		// - ① buf = name.getBytes("utf-8");
		// - ② System.out.println("Value 1 : " + new String(buf, "utf-8"));
		// 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓
		
		/*
		※ check~!!!

		   문자열을 euc-kr 인코딩 방식에서 utf-8 방식으로 변한하겠다는 의도로
		   위와 같이 코딩을 해버리면...
		   이러한 변환(잘못된 변환)으로 인해 배열이 깨져서
		   이 이후에는... euc-kr 이든... utf-8 이든...
		   어떠한 바이트 배열로 읽어오든
		   결과물이 깨져 있는 것을 확인할 수 있다.

		   이미 깨져서 생성된 String 객체의 바이트 배열은
		   어떤 방식으로든 복구가 불가능하다.

		*/



	}
}​
/*==============================================
  ■■■ 자바의 주요(중요) 클래스 ■■■
  - 자바에서 기본적으로 제공하는 주요 클래스들
  - StringTokenizer 클래스 (개념만 숙지~!!!)
================================================*/

/*
○ StringTokenizer 클래스는
   
   문자열 파싱(parsing)을 위한 정보를 제공하는 클래스로
   파싱(parsing)하고자 하는 문자열을 인자로 받아 생성하는데,
   여기에서 사용되는 파싱(parsing) 이라는 개념은
   하나의 문자열을 여러 문자열로 나누는 작업을 의미하게 되며,
   이 때 나누는 단위가 되는 문자열을 토큰(token)이라고 한다.

   StringTokenizer 클래스를 사용하기 위해서는
   java.util. 패키지의 StringTokenizer 를 import 해야 한다.

   StringTokenizer 클래스는 호환성을 유지하는 목적으로 
   보관 유지되고 있으며, 문자열을 파싱(parsing)하기 위해서는
   String 클래스의 split() 메소드나, javax.util.regex 패키지를
   사용할 것을 권장하고 있다.



○ 생성자
   
   - 원형
     StringTokenizer(String str)
	 StringTokenizer(String str, String delim)
	 StringTokenizer(String str, String delim, boolean returnDelims)
	 : 주어진 문자열 str 을 단어로 분리하는 객체를 생성하며
	   공백(구분) 문자는 delim 에 포함된 문자로 처리하게 된다.
	   만약 returnDelims 가 true 이면
	   구분 문자도 분리된 데이터로 처리하게 된다.

*/

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.StringTokenizer;

public class Test140
{
	public static void main(String[] args) throws IOException
	{
		String strTemp;
		String[] strArr;
		int n;


		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		
		System.out.print("파싱할 문자열 입력(컴마 구분) : " );
		strTemp = br.readLine();
		//-- "사과, 딸기, 바나나, 포도"

		// StringTokenizer 클래스 인스턴스 생성
		StringTokenizer st = new StringTokenizer(strTemp, ",");
		//-- strTemp 를 대상 문자열로... ("사과, 딸기, 바나나, 포도");
		//   『","』를 구분자로...

		// 테스트(확인)
		System.out.println(st.countTokens());
		//--==>> 파싱할 문자열 입력(컴마 구분) : 사과,딸기,바나나,포도
		//       4
		//-- StringTokenizer 의 『int countTokens()』 메소드
		//   : 파싱된 문자열의 개수를 반환(리턴)한다.


		strArr = new String[st.countTokens()];
		//                 -------------------
		//                         4

		// → strArr = new String[4];
		
		n = 0;
		
		// 	hasMoreTokens()
		//  이 토크나이저의 문자열에서 사용 가능한 토큰이 더 있는지 테스트합니다.
		//  문자열을 읽어들이는 입장에서... 
		//  hasMoretokens() → 다음 값이 있는지 없는지만 알려주는 메소드. (반환값 boolean)
		//  nextToken() → 실제로 문자열 "사과"를 데려오는 메소드. (반환값 String)
		//
		//  hasMoreTokens() ← 망보기
		//
		// ▼ nextToken() ← 읽어들인 문자열 "사과" 를 반환함
		//===============================
		// "사과" "딸기" "바나나" "포도"
		//===============================
		
		while(st.hasMoreTokens())	// true true true true false
		{
			strArr[n++] = st.nextToken();
			// strArr[0] = st.nextToken();
			//             --------------
			
			// strArr[0] = "사과";
			// strArr[1] = "딸기";
			// strArr[2] = "바나나";
			// strArr[3] = "포도";

		
		}   

		//-- 『hasMoreTokens』
		//    : 사용할 수 있는 토큰이 남아있는 경우 true 를 반환.
		//      더 이상 사용할 토큰이 없는 경우 false 를 반환.
		//      확인에 대한 결과만 반환할 뿐...
		//      실제 내용을 읽어들이지도 않고,
		//      실제 내용을 읽어들이는 헤드를 이동시키지도 않는다.

		//-- 『nextToken()』
		//    : 다음 토큰을 얻어온다.
		//      다음 토큰을 얻어오면헤드를 이동시키게 된다.
		//      구분자를 바꾸었을 경우 다음 호출에도
		//      바뀐 구분자를 이용하여 토큰을 분리한다.
		

		System.out.print("파싱된 토큰(문자열) : ");
		for(String str : strArr)
			System.out.print(str + " ");
		System.out.println();

		//--==>> 파싱된 토큰(문자열) : 사과 딸기 바나나 포도
		//       계속하려면 아무 키나 누르십시오 . . .
		    
		
		




	}
}