자바로 작성된 퓨니코드 소스Java2024. 2. 6. 16:28
Table of Contents
반응형
Punycode란?
Punycode는 인터넷 도메인 이름에 사용되는 유니코드 문자열을 ASCII 문자만으로 구성된 문자열로 변환하는 인코딩 방식입니다. 이 방식은 유니코드 문자를 포함하는 국제화된 도메인 이름(Internationalized Domain Names, IDNs)을 지원하기 위해 사용됩니다.
이 코드의 주요 구성 요소
- 변수 선언: 클래스의 시작 부분에는 Punycode 인코딩에 사용되는 여러 상수들이 선언되어 있습니다. 이들은 Punycode 알고리즘의 핵심 파라미터로 작용합니다.
- encode 메소드: 유니코드 문자열을 Punycode로 인코딩하는 메소드입니다. 이 메소드는 기본 ASCII 문자를 그대로 두고 나머지 문자들을 특별한 형식으로 변환합니다.
- decode 메소드: Punycode로 인코딩된 문자열을 원래의 유니코드 문자열로 디코딩합니다. 이 과정은 encode의 역과정으로 볼 수 있습니다.
- adapt 함수: Punycode 인코딩에서 사용되는 바이어스 적응 알고리즘을 구현한 함수입니다. 이는 Punycode 알고리즘의 핵심 부분 중 하나입니다.
- 기타 유틸리티 메소드들:
isBasic
,digit2codepoint
,codepoint2digit
와 같은 메소드들은 Punycode 인코딩 및 디코딩 과정에서 필요한 기본적인 연산을 수행합니다.
Punycode의 중요성
Punycode는 글로벌 인터넷 커뮤니티에서 매우 중요한 역할을 합니다. 다양한 언어와 문자 체계를 사용하는 전 세계 사용자들이 자신들의 언어로 도메인 이름을 등록하고 사용할 수 있게 해주기 때문입니다. 이는 인터넷의 국제화 및 접근성을 크게 향상시키는 요소입니다.
코드 구현의 이해와 분석
이 코드는 Java로 작성되었으며, Punycode 인코딩 및 디코딩의 복잡한 로직을 잘 캡슐화하고 있습니다. 각 메소드와 알고리즘의 세부 사항을 이해하는 것은 컴퓨터 과학과 문자 인코딩에 관심이 있는 사람들에게 유용한 연습이 될 것입니다.
자바로 작성된 퓨니코드 소스입니다.
/**
* Copyright (C) 2004 Free Software Foundation, Inc.
*
* Author: Oliver Hitz
*
* This file is part of GNU Libidn.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
public class Punycode {
/* Punycode parameters */
final static int TMIN = 1;
final static int TMAX = 26;
final static int BASE = 36;
final static int INITIAL_N = 128;
final static int INITIAL_BIAS = 72;
final static int DAMP = 700;
final static int SKEW = 38;
final static char DELIMITER = '-';
/**
* Punycodes a unicode string.
*
* @param input
* Unicode string.
* @return Punycoded string.
*/
public static String encode(String input) throws PunycodeException {
int n = INITIAL_N;
int delta = 0;
int bias = INITIAL_BIAS;
StringBuffer output = new StringBuffer();
// Copy all basic code points to the output
int b = 0;
for (int i = 0; i < input.length(); i++) {
char c = input.charAt(i);
if (isBasic(c)) {
output.append(c);
b++;
}
}
// Append delimiter
if (b > 0) {
output.append(DELIMITER);
}
int h = b;
while (h < input.length()) {
int m = Integer.MAX_VALUE;
// Find the minimum code point >= n
for (int i = 0; i < input.length(); i++) {
int c = input.charAt(i);
if (c >= n && c < m) {
m = c;
}
}
if (m - n > (Integer.MAX_VALUE - delta) / (h + 1)) {
throw new PunycodeException(PunycodeException.OVERFLOW);
}
delta = delta + (m - n) * (h + 1);
n = m;
for (int j = 0; j < input.length(); j++) {
int c = input.charAt(j);
if (c < n) {
delta++;
if (0 == delta) {
throw new PunycodeException(PunycodeException.OVERFLOW);
}
}
if (c == n) {
int q = delta;
for (int k = BASE;; k += BASE) {
int t;
if (k <= bias) {
t = TMIN;
} else if (k >= bias + TMAX) {
t = TMAX;
} else {
t = k - bias;
}
if (q < t) {
break;
}
output.append((char) digit2codepoint(t + (q - t) % (BASE - t)));
q = (q - t) / (BASE - t);
}
output.append((char) digit2codepoint(q));
bias = adapt(delta, h + 1, h == b);
delta = 0;
h++;
}
}
delta++;
n++;
}
return output.toString();
}
/**
* Decode a punycoded string.
*
* @param input
* Punycode string
* @return Unicode string.
*/
public static String decode(String input) throws PunycodeException {
int n = INITIAL_N;
int i = 0;
int bias = INITIAL_BIAS;
StringBuffer output = new StringBuffer();
int d = input.lastIndexOf(DELIMITER);
if (d > 0) {
for (int j = 0; j < d; j++) {
char c = input.charAt(j);
if (!isBasic(c)) {
throw new PunycodeException(PunycodeException.BAD_INPUT);
}
output.append(c);
}
d++;
} else {
d = 0;
}
while (d < input.length()) {
int oldi = i;
int w = 1;
for (int k = BASE;; k += BASE) {
if (d == input.length()) {
throw new PunycodeException(PunycodeException.BAD_INPUT);
}
int c = input.charAt(d++);
int digit = codepoint2digit(c);
if (digit > (Integer.MAX_VALUE - i) / w) {
throw new PunycodeException(PunycodeException.OVERFLOW);
}
i = i + digit * w;
int t;
if (k <= bias) {
t = TMIN;
} else if (k >= bias + TMAX) {
t = TMAX;
} else {
t = k - bias;
}
if (digit < t) {
break;
}
w = w * (BASE - t);
}
bias = adapt(i - oldi, output.length() + 1, oldi == 0);
if (i / (output.length() + 1) > Integer.MAX_VALUE - n) {
throw new PunycodeException(PunycodeException.OVERFLOW);
}
n = n + i / (output.length() + 1);
i = i % (output.length() + 1);
output.insert(i, (char) n);
i++;
}
return output.toString();
}
public final static int adapt(int delta, int numpoints, boolean first) {
if (first) {
delta = delta / DAMP;
} else {
delta = delta / 2;
}
delta = delta + (delta / numpoints);
int k = 0;
while (delta > ((BASE - TMIN) * TMAX) / 2) {
delta = delta / (BASE - TMIN);
k = k + BASE;
}
return k + ((BASE - TMIN + 1) * delta) / (delta + SKEW);
}
public final static boolean isBasic(char c) {
return c < 0x80;
}
public final static int digit2codepoint(int d) throws PunycodeException {
if (d < 26) {
// 0..25 : 'a'..'z'
return d + 'a';
} else if (d < 36) {
// 26..35 : '0'..'9';
return d - 26 + '0';
} else {
throw new PunycodeException(PunycodeException.BAD_INPUT);
}
}
public final static int codepoint2digit(int c) throws PunycodeException {
if (c - '0' < 10) {
// '0'..'9' : 26..35
return c - '0' + 26;
} else if (c - 'a' < 26) {
// 'a'..'z' : 0..25
return c - 'a';
} else {
throw new PunycodeException(PunycodeException.BAD_INPUT);
}
}
}
PunycodeException 클래스입니다.
public class PunycodeException extends Exception {
public static String OVERFLOW = "Overflow.";
public static String BAD_INPUT = "Bad input.";
/**
* Creates a new PunycodeException.
*
* @param m
* message.
*/
public PunycodeException(String m) {
super(m);
}
}
반응형
@위피M :: ChatGPT로 여는 새로운 세상!!
ChatGPT, 블록체인, 자바, 맥북, 인터넷, 컴퓨터 정보를 공유합니다.
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!