자바 문자 집합 사기 성

6531 단어 자바
저자: mindwind @ 구름 아래 산꼭대기
"몇 년 동안 난 코드 문 제 는 프로그래머 의 마음 속 의 아픔 이 었 어 요.
얼마나 많은 프로그래머 가 난 코드 속 에 흐 트 러 져 도 문자 집합 이 보이 지 않 는 웃음 을 짓 고 있 는 지. "
----------------------------------------------------------------------------------
오늘 한 동료 가 갑자기 나 를 찾 아 왔 는데, 우리 사이 의 온라인 시스템 인터페이스 가 갑자기 돌아 와 서 소식 이 중국어 로 어 지 러 워 졌 다 고 말 했다.
그 전에 인 터 페 이 스 는 정상 이 었 으 나 코드 는 그 동안 변경 되 지 않 았 다 는 것 을 인정 했다.
프로그램 코드 가 바 뀌 지 않 았 다 고 했 으 니 환경 이 바 뀌 었 을 것 이 라 고 먼저 추측 했다.
인터페이스 가 되 돌아 오 는 메 시 지 를 어떻게 처리 하 는 지 물 어 봤 더 니 문자열 문자 집합 인 코딩 변환 을 했다 며 코드 를 붙 여 보라 고 했다.
new String(msg.getBytes(), Charset.forName("GBK"));
그래서 위 에 있 는 낯 익 은 코드 세 션 을 보 았 습 니 다. 이 코드 는 무슨 뜻 입 니까?
"msg 문자열 을 기본 인 코딩 에서 GBK 인 코딩 으로 바 꾸 는 것" 이 라 고 말 할 수도 있다.
이렇게 생각 하 는 것 은 이미 편 차 를 이해 하 는 것 이 아니 라, 전혀 다른 것 이다.
위의 줄 코드 는 String 류 의 두 api 를 사 용 했 습 니 다.
publicbyte[] getBytes()
public String(byte bytes[], Charset charset)
String 클래스 는 자바 에서 가장 자주 사용 되 고 가장 많이 사용 되 는 클래스 라 고 하 니 논란 이 없 을 것 입 니 다.
그러나 많은 사람들 이 이 가장 익숙 한 자바 doc 를 자세히 보지 못 했 을 것 이다.
getBytes () 의 자바 doc 는 다음 과 같 습 니 다:
Encodes thisStringinto a sequence of bytes using the platform's default charset, storing the result into a new byte array.
이 문자열 을 플랫폼 의 기본 문자 집합 으로 인 코딩 하여 바이트 시퀀스 로 되 돌아 오 는 바이트 배열 에 저장 한 다 는 뜻 입 니 다.
또 다른 구조 함수 api 의 자바 doc 는:
Constructs a newStringby decoding the specified array of bytes using the specifiedcharset.
지정 한 문자 집합 디 코딩 바이트 배열 을 사용 하여 새로운 문자열 을 만 든 다 는 뜻 입 니 다.
자바 doc 의 설명 을 통 해 우 리 는 이 구조 함수 가 지정 한 문자 집합 은 첫 번 째 매개 변수 바이트 배열 을 디 코딩 하 는 데 사용 되 는 것 이지 이 문자 집합 으로 새로운 문자열 을 만 드 는 것 을 표현 하 는 것 이 아니 라 는 것 을 알 게 되 었 다.
그렇다면 위의 그 줄 코드 는 사실 무슨 뜻 을 표현 하고 있 는 것 일 까? 여기 서 곧 나 올 것 이다.
이 문자열 은 플랫폼 의 기본 인 코딩 을 바이트 배열 로 사용 하고 이 바이트 배열 을 기반 으로 GBK 를 통 해 디 코딩 을 하여 새로운 문자열 을 만 듭 니 다.
그러면 이 과정 에서 무슨 일이 일 어 났 습 니까? 문자열 인 코딩 은 우리 가 원 하 는 플랫폼 에서 기본 값 으로 GBK 로 바 뀌 었 습 니까?그렇게 생각하면 정말 멍청 하고 순진 하 다.
사실 위의 코드 의 실행 과정 에서 플랫폼 의 기본 인 코딩 이 GBK 라면 이 코드 는 새로운 문자열 을 만 들 었 고 원래 msg 와 같 으 며 부작용 이 없고 열심히 하지 않 았 습 니 다.
앞서 언급 된 인터페이스 난 장 판 의 문 제 는 기 존 상대 플랫폼 인 코딩 이 GBK 였 다가 어제 갑자기 UTF - 8 로 바 뀌 면서 발생 한 난 장 판 때 문 이 었 다.
프로그램 원작 자가 기대 하 는 인 코딩 변환 과정 은 전혀 필요 하지 않 습 니 다. 자바 에서 문자열 의 인 코딩 은 유 니 코드 문자 집합 을 통일 적 으로 사 용 했 기 때 문 입 니 다.
String 대상 의 구조 과정 은 문자 집합 인 코딩 을 지정 한 바이트 배열 을 유 니 코드 인 코딩 문자열 로 변환 하 는 것 입 니 다.
자바 에서 GBK 인 코딩 문자열 을 말 하 는 지 ISO - 8859 - 1 인 코딩 문자열 은 모두 터 무 니 없 는 말이다.
그러면 우리 가 웹 개발 에서 자주 사용 하 는 코드 전환 방식 이자 익숙 한 코드 가 누 군 가 를 곤 혹 스 럽 게 할 수 있 습 니 다. 다음 과 같 습 니 다.
new String(request.getParameter("xxxx").getBytes("iso-8859-1"),"utf-8")
위의 이 코드 는 tomcat 를 바탕 으로 개발 한 일부 웹 응용 에서 코드 를 바 꾸 는 데 효과 가 있 습 니 다. 이것 은 또 왜 입 니까?
이 유 는 브 라 우 저 에서 들 어 오 는 요청 매개 변 수 를 기본 으로 사용 하 는 utf - 8 인 코딩 이 고, tomcat 에서 요청 을 받 은 후 기본 적 인 iso - 8859 - 1 디 코딩 으로 잘못된 문자열 인 자 를 만 들 었 기 때 문 입 니 다.
복원 하려 면 먼저 문자열 을 원본 바이트 배열 로 복원 한 다음 utf - 8 을 통 해 정확 한 문자열 을 디 코딩 하여 생 성 해 야 하기 때문에 위 와 같은 방법 이 있 습 니 다.
위 와 같이 흐리멍덩 한 프로그래머 에 대해 iso - 8859 - 1 의 문자열 을 utf - 8 형식의 문자열 로 변환 하 는 것 으로 오인 합 니 다.(이것 도 부 끄 러 울 것 이 없다. 나 도 몇 년 동안 이렇게 생각 했다.)
그러나 문자 집합 인 코딩 변환 은 마이너스 가 그렇게 간단 한 것 이 아 닙 니 다. 우리 가 정확하게 변환 할 수 있 는 이 유 는 iso - 8859 - 1 의 문자 집합 이 단일 바이트 문자 집합 인 코딩 이기 때 문 입 니 다.
다음은 간단 한 예 를 들 어 문자 집합 인 코딩 변환 문 제 를 설명 한다.
		//         
		Charset iso88591 = Charset.forName("iso-8859-1");
		//         
		Charset big5 = Charset.forName("big5");
		//          
		Charset utf8 = Charset.forName("utf-8");
		
		
		//       
		String src = "  ";                
		// utf8        
		byte[] utf8Bytes = src.getBytes(utf8);    
		//    iso-8859-1         (  )
		String wrongStr = new String(utf8Bytes, iso88591);   
		//    big5         (    )
		String wrongStr2 = new String(utf8Bytes, big5);
		
		
		System.out.println("wrongStr-iso88591-decoding = " + wrongStr + "    len=" + wrongStr.length());
		System.out.println("wrongStr-big5-decoding     = " + wrongStr2 + "   len=" + wrongStr2.length());
		System.out.println("orignal-utf8-bytes         = " + Arrays.toString(utf8Bytes));
		
		
		//   iso-8859-1           utf8        -   
		byte[] resumeBytes = wrongStr.getBytes(iso88591);   
		String rightStr = new String(resumeBytes, utf8);
		
		
		//   big5           utf8        -    
		byte[] resumeBytes2 = wrongStr2.getBytes(big5);
		String rightStr2 = new String(resumeBytes2, utf8);
		
		
		System.out.println("resume-iso88591-utf8-bytes = " + Arrays.toString(resumeBytes));
		System.out.println("resume-big5-utf8-bytes     = " + Arrays.toString(resumeBytes2));
		System.out.println(rightStr);
		System.out.println(rightStr2);

원본 문자열 src, 우선 utf - 8 바이트 배열 로 인 코딩 합 니 다.
iso - 8859 - 1 단일 바이트 문자 집합 디 코딩 으로 잘못된 문자열 wrongStr 를 얻 었 습 니 다.
빅 5 바이트 문자 집합 디 코딩 으로 잘못된 문자열 wrong Str 2 를 얻 었 습 니 다.
두 개의 잘못된 문자열 을 getBytes (charset) 로 호출 하여 원본 바이트 배열 로 복원 하고 정확 한 인 코딩 utf - 8 디 코딩 을 사용 하여 정확 한 문자열 을 만 들 려 고 합 니 다.
다음 출력 결 과 를 볼 수 있 습 니 다:
wrongStr - iso 88591 - decoding = 전체 181 ° len = 6 wrongStr - igg 5 - decoding = 전체 30234 °?len = 3 orignal - utf8 - bytes = [- 26, - 75, - 117, - 24, - 81, - 107] resume - iso 88591 - utf8 - bytes = [- 26, - 75, - 117, - 24, - 81, - 107] resume - big5 - utf8 - bytes = [- 26, - 75, 63, 63] test???
중국어 '테스트' 두 글 자 는 utf - 8 인 코딩 을 사용 합 니 다. 이 두 글 자 는 각각 3 개의 바이트 로 모두 6 개의 바이트 입 니 다.
iso - 8859 - 1 은 단일 바이트 문자 집합 에 속 하 며, 디 코딩 으로 생 성 된 문자열 문자 와 바이트 가 일일이 대응 하기 때문에 디 코딩 된 어 지 러 운 문자열 wrong Str 길 이 는 6 입 니 다.
한편, 빅 5 는 두 바이트 문자 집합 에 속 하고 디 코딩 으로 생 성 된 문자열 은 두 바이트 마다 한 글자 씩 대응 하기 때문에 디 코딩 후의 어 지 러 운 문자열 wrong Str 2 길 이 는 3 입 니 다.
위 와 같이 [- 26, - 75] 바이트 조합 은 빅 5 문자 [瘚] 로 디 코딩 되 었 고 바이트 조합 [- 117, - 24] 과 [- 81, - 107] 은 빅 5 에 대응 하 는 문자 가 없어 서 [??] 로 디 코딩 되 었 다.
큰 문자 집합 바이트 시퀀스 에서 작은 문자 집합 문자열 로 디 코딩 할 때 디 코딩 을 잃 어 버 리 고 되 돌 릴 수 없 기 때문에 다음 에 우리 가 빅 5 로 인 코딩 을 할 때 원래 의 바이트 시퀀스 가 아 닙 니 다.
마지막 으로, 우 리 는 자바 인 코딩 문 제 를 처리 할 때 몇 가지 개념 을 분명하게 구분 해 야 한다.
1. 자바 문자열, 내부 통합 유 니 코드 문자 집합 사용
2. 자바 문자열 사이 에는 문자 집합 변환 이 존재 하지 않 습 니 다. 바이트 시퀀스 사이 에 만 문자 집합 변환 이 존재 합 니 다.
추가 설명:
유 니 코드 는 기호 집합 으로 기호의 바 이 너 리 코드 를 규정 하 였 으 나 어떻게 저장 하 는 지 규정 하지 않 았 다. 현재 의 규 모 는 100 여 만 가지 기 호 를 수용 하고 있다.
유 니 코드 의 서로 다른 저장 방식 은 유 니 코드 의 다양한 실현 방식 을 대표 합 니 다.
utf - 8 은 유 니 코드 의 실현 방식 일 뿐, 유사 한 것 은 utf - 16, utf - 32 도 있다.
자바 의 문자열 과 jvm 이 실 행 될 때 모두 utf - 16 형식 을 사용 합 니 다.

좋은 웹페이지 즐겨찾기