메인 컨텐츠로 가기

developerWorks 이용 약관에 동의하시는 경우 제출을 클릭하십시오. 이용 약관 보기.

developerWorks에 처음 로그인하면 developerWorks프로파일이 생성됩니다.귀하의 프로파일에서 동의하신 내용이 공개되지만 이 사항은 언제든지 변경 가능합니다. 귀하의 성명(숨김으로 체크되어 있어도 표시됩니다)과 디스플레이 이름은 게시한 컨텐츠나 사이트 엑세스시 표시됩니다.

모든 정보가 안전하게 전송되었습니다.

  • 닫기 [x]

처음 developerWorks에 로그인할 때 프로파일이 작성되므로, 이를 위해 디스플레이 이름을 선택해야 합니다. 선택하신 디스플레이 이름은 developerWorks에 게시한 컨텐츠에 표시됩니다.

3글자 이상 31글자 이하의 길이로 사용 가능합니다. dW커뮤니티 내에서는 보안상 이메일주소를 제외한 다른 이름을 지정하셔야 합니다.

developerWorks 이용 약관에 동의하시는 경우 제출을 클릭하십시오. 이용 약관 보기.

모든 정보가 안전하게 전송되었습니다.

  • 닫기 [x]

Java 언어를 이용한 유니코드 서로게이트 프로그래밍

코딩 옵션 및 성능 고려사항

Masahiko Maedera, Software engineer, <a href="http://www.ibm.com/">IBM</a>
Masahiko Maedera is a software engineer at the Yamato Software Development Laboratory (YSL), IBM Japan, and a member of Globalization Center of Competency. He worked on the design and implementation of string libraries in Lotus Notes/Domino.

요약:  버전 1.5 이후로, Java™ 버전 1.5 이후로, Java 언어는 단일 16비트 char 데이터 유형으로 표시할 수 없는 유니코드 보조 문자를 지원하는 API를 제공했습니다. 이 기사에서는 이런 API의 특징과 올바른 사용법을 설명하고 API의 처리 성능을 평가합니다.

원문 게재일:  2010 년 8 월 24 일 번역 게재일:   2010 년 11 월 30 일
난이도:  중급 원문:  보기 PDF:  A4 and Letter (127KB | 18 pages)Get Adobe® Reader®
페이지뷰:  3314 회
의견:  


초기 Java 버전에서는 16비트 char 데이터 유형을 사용하여 유니코드 문자를 표시했다. 당시에는 모든 유니코드 문자가 65,535(0xFFFF) 미만의 값을 가지고 있었고 16비트로 표현할 수 있었기 때문에 이런 디자인이 통했다. 하지만, 이후로 유니코드가 최대 1,114,111(0x10FFFF)의 값까지 증가했다. 16비트 값은 유니코드 버전 3.1에서 모든 유니코드 문자를 표시하기에 너무 작았기 때문에, UTF-32 인코딩 스킴에 대해 32비트 값(코드 포인트라고 함)이 채택되었다.

그러나 효율적인 메모리 사용을 위해 32비트 값보다는 16비트 값을 선호하므로, 유니코드는 16비트 값을 계속 사용할 수 있도록 허용하는 새로운 디자인을 도입했다. UTF-16 인코딩 스킴에서 채택된 이 디자인에서는 16비트 high surrogate에 1,024개의 값을 지정하고 16비트 low surrogate에도 다른 1,024개의 값을 지정한다. 이 디자인에서는 high surrogate 다음에 low surrogate를 사용하여(서로게이트 쌍) 65,536(0x10000)과 1,114,111(0x10FFFF) 사이에 있는 1,048,576(0x100000)개(즉, 1,024×1,024개)의 값을 표시한다.

Java 1.5에서는 (기존 프로그램과의 호환성을 위해) UTF-16 값을 표시하려고 char 유형의 작동을 그대로 유지했고, UTF-32 값을 표시하기 위해 코드 포인트의 개념을 구현했다. (JSR 204: 유니코드 보조 문자 지원에 따라 구현된) 이 확장에서는 유니코드 코드 포인트의 정확한 값이나 변환 알고리즘을 기억할 필요가 없지만, 서로게이트 API의 올바른 사용법을 이해하는 것이 중요하다.

동아시아 국가 및 지역에서는 사용자의 요구에 부응하여 최근 몇 년 사이에 문자 세트 표준의 문자 수를 크게 늘렸다. 이런 표준에 중국 국가 표준 조직의 GB 18030과 일본 국가 표준 조직의 JIS X 0213이 포함된다. 따라서 프로그램들이 유니코드 서로게이트 쌍을 지원하기 위해 이런 표준을 준수할 필요성이 점점 커지고 있다. 이 기사에서는 소프트웨어를 char 유형의 문자만 지원하는 버전에서 서로게이트 쌍을 처리할 수 있는 새 버전으로 리디자인할 계획을 가진 독자들을 위해 관련 Java API 및 코딩 옵션을 설명한다. 또한, 서로게이트 쌍을 위한 지원을 추가하면 처리 시간에 어떤 영향을 미치는지도 평가해본다.

순차 액세스

순차 액세스는 Java 언어로 문자열을 처리하기 위한 기본 작업 중 하나다. 이 접근 방식에서는 앞에서 뒤로 또는 때때로 뒤에서 앞으로 순차적으로 입력 문자열의 각 문자에 액세스한다. 이 섹션에서는 순차 액세스를 사용하여 문자열에서 32비트 코드 포인트 배열을 작성하기 위한 기법을 설명한 7개의 예제를 살펴보고, 그 처리 시간을 평가한다.

예제 1-1: 벤치마크(서로게이트 쌍에 대한 지원 없음)

목록 1에서는 서로게이트 쌍에 관심을 두지 않고 32비트 코드 포인트 값에 16비트 char 유형의 값을 직접 지정한다.


목록 1. 서로게이트 쌍에 대한 지원 없음

int[] toCodePointArray(String str) { // Example 1-1
    int len = str.length();          // the length of str
    int[] acp = new int[len];        // an array of code points

    for (int i = 0, j = 0; i < len; i++) {
        acp[j++] = str.charAt(i);
    }
    return acp;
}

이 예제에서는 서로게이트 쌍을 지원하지 않지만, 이후의 순차 액세스 예제와 비교하기 위한 처리 시간 벤치마크를 제공한다.

예제 1-2: isSurrogatePair() 사용

목록 2에서는 isSurrogatePair()를 사용하여 서로게이트 쌍의 총 개수를 계산한다. 계산이 끝나면 코드 포인트 배열에 적당한 메모리를 할당하여 값을 저장한다. 다음으로, 순차 액세스 루프로 들어가서 isHighSurrogate()isLowSurrogate()를 사용하여 각 서로게이트 문자가 high surrogate인지, low surrogate인지 결정한다. High surrogate 다음에 low surrogate가 나오는 것으로 밝혀지면, toCodePoint()를 사용하여 서로게이트 쌍을 코드 포인트 값으로 변환하고 현재 인덱스를 2씩 증가시킨다. 그렇지 않으면, char 유형의 값을 직접 코드 포인트 값으로 지정하여 현재 인덱스를 1씩 증가시킨다. 처리 시간은 예제 1-1에서의 처리 시간보다 1.38배 더 길다.


목록 2. 제한적 지원
int[] toCodePointArray(String str) { // Example 1-2
    int len = str.length();          // the length of str
    int[] acp;                       // an array of code points
    int surrogatePairCount = 0;      // the count of surrogate pairs

    for (int i = 1; i < len; i++) {
        if (Character.isSurrogatePair(str.charAt(i - 1), str.charAt(i))) {
            surrogatePairCount++;
            i++;
        }
    }
    acp = new int[len - surrogatePairCount];
    for (int i = 0, j = 0; i < len; i++) {
        char ch0 = str.charAt(i);         // the current char
        if (Character.isHighSurrogate(ch0) && i + 1 < len) {
            char ch1 = str.charAt(i + 1); // the next char
            if (Character.isLowSurrogate(ch1)) {
                acp[j++] = Character.toCodePoint(ch0, ch1);
                i++;
                continue;
            }
        }
        acp[j++] = ch0;
    }
    return acp;
}

목록 2와 같이 순진한 방법으로 소프트웨어를 업데이트하는 것은 문제가 있다. 이 방법은 지루한데다 광범위한 수정 작업도 필요하므로, 최종 소프트웨어가 취약하고 나중에 변경하기 어려워진다. 특히, 다음과 같은 문제점이 있다.

  • 충분한 메모리 할당을 위해 코드 포인트 수를 계산할 필요성
  • 문자열에서 지정된 인덱스에 대해 올바른 코드 포인트 값을 얻기 어려움
  • 다음 처리 단계를 위해 현재 인덱스를 올바로 이동하기 어려움

다음 예제에서 개선된 알고리즘이 표시된다.

예제 1-3: 기본 지원

Java 1.5에서는 예제 1-2의 세 가지 문제점을 각각 해결하기 위해 codePointCount(), codePointAt()offsetByCodePoints() 메소드를 제공했다. 목록 3에서는 이들 메소드를 사용하여 알고리즘의 가독성을 개선한다.


목록 3. 기본 지원
int[] toCodePointArray(String str) { // Example 1-3
    int len = str.length();          // the length of str
    int[] acp = new int[str.codePointCount(0, len)];

    for (int i = 0, j = 0; i < len; i = str.offsetByCodePoints(i, 1)) {
        acp[j++] = str.codePointAt(i);
    }
    return acp;
}

하지만, 목록 3에 대한 처리 시간은 목록 1에 비해 2.80배 더 길다.

예제 1-4: codePointBefore() 사용

offsetByCodePoints()에서 음수를 두 번째 매개변수로 받을 때, 문자열 헤드 쪽으로 절대 오프셋을 계산할 수 있다. 다음으로, codePointBefore()는 지정된 인덱스 직전에 코드 포인트 값을 리턴할 수 있다. 목록 4에서 이런 메소드를 사용하여 뒤에서 앞으로 문자열을 순회한다.


목록 4. codePointBefore()를 이용한 기본 지원
int[] toCodePointArray(String str) { // Example 1-4
    int len = str.length();          // the length of str
    int[] acp = new int[str.codePointCount(0, len)];
    int j = acp.length;              // an index for acp

    for (int i = len; i > 0; i = str.offsetByCodePoints(i, -1)) {
        acp[--j] = str.codePointBefore(i);
    }
    return acp;
}

이 예제에서의 처리 시간(예제 1-1에 비해 2.72배의 시간이 걸림)은 예제 1-3보다 다소 빠르다. 일반적으로, 0이 아닌 값보다는 0과 비교할 때 JVM의 코드 크기가 더 작고, 이렇게 하면 가끔 성능이 개선된다. 하지만, 이런 작은 개선이 가독성 손실보다 가치가 없을 수도 있다.

예제 1-5: charCount() 사용

예제 1-31-4에서는 서로게이트 쌍을 위한 기본 지원을 제공한다. 이 두 예제는 임시 변수가 필요 없는 강력한 코딩 방식이다. 처리 시간 단축을 위해 offsetByCodePoints() 대신 charCount()를 사용하는 것이 효과적이지만, 목록 5에 표시된 것처럼 임시 변수가 코드 포인트 값을 보유하고 있어야 한다.


목록 5. charCount()를 이용해 최적화된 지원
int[] toCodePointArray(String str) { // Example 1-5
    int len = str.length();          // the length of str
    int[] acp = new int[str.codePointCount(0, len)];
    int j = 0;                       // an index for acp

    for (int i = 0, cp; i < len; i += Character.charCount(cp)) {
        cp = str.codePointAt(i);
        acp[j++] = cp;
    }
    return acp;
}

목록 5에 대한 처리 시간이 예제 1-1에 비해 1.68배로 단축된다.

예제 1-6: char 배열에 액세스

목록 6에서는 예제 1-5에 표시된 최적화를 사용하는 동안 char 유형의 배열에 직접 액세스한다.


목록 6. char 배열을 이용해 최적화된 지원
int[] toCodePointArray(String str) { // Example 1-6
    char[] ach = str.toCharArray();  // a char array copied from str
    int len = ach.length;            // the length of ach
    int[] acp = new int[Character.codePointCount(ach, 0, len)];
    int j = 0;                       // an index for acp

    for (int i = 0, cp; i < len; i += Character.charCount(cp)) {
        cp = Character.codePointAt(ach, i);
        acp[j++] = cp;
    }
    return acp;
}

char 배열은 toCharArray()를 사용하여 문자열에서 복사된다. 배열에 직접 액세스하는 것이 메소드를 통한 간접 액세스보다 빠르기 때문에 성능이 개선된다. 처리 시간은 예제 1-1의 처리 시간보다 1.51배 길다. 하지만, toCharArray()를 호출할 때 이 배열에 새 어레이를 작성하고 데이터를 이 배열로 복사하는 데 약간의 오버헤드가 있다. String 클래스에서 제공하는 편리한 메소드를 사용할 수 없다. 그래도 이 알고리즘은 대량의 데이터를 처리하는 데 유용하다.

예제 1-7: 오브젝트 지향 알고리즘

목록 7에 표시된 것처럼, 이 예제의 오브젝트 지향 알고리즘에서는 CharBuffer 클래스를 사용한다.


목록 7. CharSequence를 이용한 오브젝트 지향 접근 방식
int[] toCodePointArray(String str) {        // Example 1-7
    CharBuffer cBuf = CharBuffer.wrap(str); // Buffer to wrap str
    IntBuffer iBuf = IntBuffer.allocate(    // Buffer to store code points
            Character.codePointCount(cBuf, 0, cBuf.capacity()));

    while (cBuf.remaining() > 0) {
        int cp = Character.codePointAt(cBuf, 0); // the current code point
        iBuf.put(cp);
        cBuf.position(cBuf.position() + Character.charCount(cp));
    }
    return iBuf.array();
}

이전 예제들과는 달리, 목록 7에서는 순차 액세스를 위한 현재 위치를 유지하기 위해 인덱스를 사용할 필요가 없다. 그 대신, CharBuffer가 현재 위치를 내부적으로 추적한다. Character 클래스는 CharSequence 인터페이스를 통해 CharBuffer를 처리할 수 있는 정적 메소드인 codePointCount()codePointAt()을 제공한다. CharBuffer는 항상 현재 위치를 CharSequence의 첫 부분으로 설정한다. 따라서 codePointAt()이 호출될 때 두 번째 매개변수가 항상 0으로 설정된다. 처리 시간은 예제 1-1에서의 처리 시간보다 2.15배 더 길다.

처리 시간 비교

순차 액세스 예제에 대한 타이밍 테스트에서는 10,000개의 서로게이트 쌍과 서로게이트가 아닌 것 10,000개를 포함한 샘플 문자열을 사용했다. 코드 포인트 배열은 문자열로부터 10,000회 작성되었으며, 테스트 환경은 다음으로 구성되었다.

  • OS: Microsoft Windows® XP Professional SP2
  • Java: IBM Java 1.5 SR7
  • CPU: Intel® Core 2 Duo CPU T8300 @ 2.40GHz
  • 메모리: 2.97GB RAM

표 1은 예제 1-1에서 1-7까지의 절대 및 상대 처리 시간과 연관된 API를 나타낸 것이다.


표 1. 순차 액세스 예제에 대한 처리 시간과 API
예제설명처리
시간
(ms)
예제 1-1에 대한
비율
API
1-1서로게이트 쌍에 대한 지원 없음20311.00
1-2제한적 지원27971.38Character 클래스:
  • static boolean isHighSurrogate(char ch)
  • static boolean isLowSurrogate(char ch)
  • static boolean isSurrogatePair(char high, char low)
  • static int toCodePoint(char high, char low)
1-3기본 지원56872.80String 클래스:
  • int codePointAt(int index)
  • int codePointCount(int begin, int end)
  • int offsetByCodePoints(int index, int cpOffset)
1-4codePointBefore()를 이용한 기본 지원55162.72String 클래스:
  • int codePointBefore(int index)
1-5charCount()를 이용해 최적화된 지원34061.68Character 클래스:
  • static int charCount(int cp)
1-6char 배열을 이용해 최적화된 지원30621.51Character 클래스:
  • static int codePointAt(char[] ach, int index)
  • static int codePointCount(char[] ach, int offset, int count)
1-7CharSequence를 이용한 오브젝트 지향 접근 방식43602.15 Character 클래스:
  • static int codePointAt(CharSequence seq, int index)
  • static int codePointCount(CharSequence seq, int begin, int end)

임의 액세스

임의 액세스는 문자열에서 임의의 위치에 대한 직접 액세스이다. 문자열에 액세스할 때, 인덱스 값은 16비트 char 유형의 단위를 기준으로 한다. 하지만, 문자열에서 32비트 코드 포인트를 사용하는 경우에는 32비트 코드 포인트의 단위를 기반으로 한 인덱스를 사용하여 액세스할 수 없다. offsetByCodePoints()를 사용하여 코드 포인트에 대한 인덱스를 char 유형에 대한 인덱스로 변환해야 한다. offsetByCodePoints()는 항상 두 번째 매개변수를 사용하여 첫 번째 매개변수에서 문자열의 내부에 대한 계산을 하기 때문에, 이는 알고리즘이 올바로 디자인되어 있지 않은 경우 성능 저하를 초래할 수 있다. 이 섹션에서는 짧은 단위를 사용하여 긴 문자열을 분리하는 세 가지 예제를 비교해본다.

예제 2-1: 벤치마크(서로게이트 쌍에 대한 지원 없음)

목록 8은 너비 단위로 문자열을 분리하는 방법을 나타낸 것이다. 이것은 서로게이트 쌍을 지원하지 않는 이후의 예제들을 위한 벤치마크이다.


목록 8. 서로게이트 쌍에 대한 지원 없음
String[] sliceString(String str, int width) { // Example 2-1
    // It must be that "str != null && width > 0".
    List<String> slices = new ArrayList<String>();
    int len = str.length();       // (1) the length of str
    int sliceLimit = len - width; // (2) Do not slice beyond here.
    int pos = 0;                  // the current position per char type

    while (pos < sliceLimit) {
        int begin = pos;                       // (3)
        int end   = pos + width;               // (4)
        slices.add(str.substring(begin, end));
        pos += width;                          // (5)
    }
    slices.add(str.substring(pos));            // (6)
    return slices.toArray(new String[slices.size()]); }

sliceLimit 변수는 문자열의 나머지가 현재 너비 단위로 분리할 수 있을 만큼 충분히 길지 않을 때 IndexOutOfBoundsException의 인스턴스를 발생시키지 않기 위해 분리 위치의 한계를 유지한다. 이 알고리즘은 현재 위치가 sliceLimit를 초과할 때 while 루프에서 이스케이프한 후 마지막 조각을 처리한다.

예제 2-2: 코드 포인트의 인덱스 사용

목록 9는 코드 포인트의 인덱스를 사용하여 문자열에 임의로 액세스하는 방법을 나타낸 것이다.


목록 9. 성능 저하
String[] sliceString(String str, int width) { // Example 2-2
    // It must be that "str != null && width > 0".
    List<String> slices = new ArrayList<String>();
    int len = str.codePointCount(0, str.length()); // (1) code point count [Modified]
    int sliceLimit = len - width; // (2) Do not slice beyond here.
    int pos = 0;                  // the current position per code point

    while (pos < sliceLimit) {
        int begin = str.offsetByCodePoints(0, pos);            // (3) [Modified]
        int end   = str.offsetByCodePoints(0, pos + width);    // (4) [Modified]
        slices.add(str.substring(begin, end));
        pos += width;                                          // (5)
    }
    slices.add(str.substring(str.offsetByCodePoints(0, pos))); // (6) [Modified]
    return slices.toArray(new String[slices.size()]); }

목록 9목록 8에서 여러 행을 변경한다. 우선, (1)행에서 length()codePointCount()로 바꾼다. 그 다음, offsetByCodePoints()를 사용하여 char 유형의 인덱스를 (3), (4), (6)행에 있는 코드 포인트의 인덱스로 바꾼다.

이 알고리즘의 기본적인 플로우는 예제 2-1과 거의 같아 보인다. 그러나 offsetByCodePoints()는 항상 앞에서 지정된 인덱스까지 문자열의 내부를 계산하기 때문에, 예제 2-1에 비해 문자열 길이에 비례하여 처리 시간이 늘어난다.

예제 2-3: 처리 시간 단축

목록 10에 표시된 접근 방식을 이용해 예제 2-2의 성능 문제를 피할 수 있다.


목록 10. 성능 개선
String[] sliceString(String str, int width) { // Example 2-3
    // It must be that "str != null && width > 0".
    List<String> slices = new ArrayList<String>();
    int len = str.length(); // (1) the length of str
    int sliceLimit          // (2) Do not slice beyond here. [Modified]
            = (len >= width * 2 || str.codePointCount(0, len) > width)
            ? str.offsetByCodePoints(len, -width) : 0;
    int pos = 0;            // the current position per char type

    while (pos < sliceLimit) {
        int begin = pos;                                // (3)
        int end   = str.offsetByCodePoints(pos, width); // (4) [Modified]
        slices.add(str.substring(begin, end));
        pos = end;                                      // (5) [Modified]
    }
    slices.add(str.substring(pos));                     // (6)
    return slices.toArray(new String[slices.size()]); }

우선, (목록 9의) len-width 표현식이 (2)행에서 offsetByCodePoints(len,-width)로 바뀐다. 하지만, 이로 인해 width의 값이 코드 포인트 수보다 클 때 IndexOutOfBoundsException의 인스턴스가 발생한다. try/catch 예외 핸들러를 포함한 절이 다른 해결책이 되겠지만, 예외를 피하기 위한 경계 조건을 고려해야 한다. 모든 코드 포인트가 서로게이트 쌍으로 변환되더라도 코드 포인트 수가 width의 값을 초과하기 때문에, len>width*2 표현식이 참인 경우 offsetByCodePoints()를 안전하게 호출할 수 있다. 또는 codePointCount(0,len)>width 표현식이 참인 경우 offsetByCodePoints()를 안전하게 호출할 수도 있다. 다른 경우에는 sliceLimit0으로 설정해야 한다.

while 루프의 (4)행에서 목록 9에 있는 pos + width 표현식을 offsetByCodePoints(pos,width)로 바꿔야 한다. 첫 번째 매개변수는 현재 위치를, 두 번째 매개변수는 width의 값을 지정하기 때문에, 필요한 계산의 양은 width 값 이내의 범위이다. 다음으로, (5)행에서 pos+=width 표현식을 pos=end 표현식으로 바꿔야 한다. 이렇게 하면 같은 인덱스를 계산하기 위해 offsetByCodePoints()를 두 번 호출하지 않아도 된다. 소스 코드를 더 많이 수정하여 처리 시간을 더 줄일 수 있다.

처리 시간 비교

그림 1과 2는 예제 2-1, 2-22-3의 처리 시간을 나타낸 것이다. 샘플 문자열에는 같은 수의 서로게이트 쌍과 비 서로게이트 쌍이 들어 있었다. 문자열 길이와 width의 값이 변경되는 동안 샘플 문자열은 10,000회 분리되었다.


그림 1. 조각의 일정한 너비
constantWidth.jpg

그림 2. 조각의 일정한 수
constantCount.jpg

예제 2-12-3에서는 길이에 비례하여 처리 시간이 증가하는 반면, 예제 2-2에서는 길이의 제곱에 비례하여 처리 시간이 증가한다. 조각의 수가 고정되어 있는 상태에서 문자열의 길이와 width의 값이 증가할 때, 예제 2-1에서는 처리 시간이 일정한 데 반해, 예제 2-22-3에서는 width의 값에 비례하여 처리 시간이 증가한다.


정보 API

서로게이트로 작업하기 위한 대부분의 정보 API에는 이름이 같은 두 가지 유형의 메소드가 있다. 하나는 16비트 char 유형으로 매개변수를 받고, 다른 하나는 32비트 코드 포인트로 매개변수를 받는다. 표 2는 각 API의 리턴 값을 나타낸 것이다. U+20B9F가 U+D842 다음에 U+DF9F가 나오는 서로게이트 쌍으로 변환될 때, 세 번째 열은 U+53F1, 네 번째 열은 U+20B9F, 마지막 열은 U+D842(high surrogate)에 대한 것이다. U+20B9F 대신 U+D842의 값을 사용하면 프로그램에서 서로게이트 쌍을 처리할 수 없는 경우 (표 2에 굵은 기울임꼴로 나타낸) 예상치 못한 결과를 초래한다.


표 2. 서로게이트용 정보 API
클래스메소드/생성자U+53F1에 대한 값U+20B9F에 대한 값U+D842에 대한 값
U53F1.jpgU20B9F.jpg
Characterstatic byte getDirectionality(int cp)000
static int getNumericValue(int cp)-1-1-1
static int getType(int cp)5519
static boolean isDefined(int cp)true true true
static boolean isDigit(int cp)false false false
static boolean isISOControl(int cp)false false false
static boolean isIdentifierIgnorable(int cp)false false false
static boolean isJavaIdentifierPart(int cp)true true false
static boolean isJavaIdentifierStart(int cp)true true false
static boolean isLetter(int cp)true true false
static boolean isLetterOrDigit(int cp)true true false
static boolean isLowerCase(int cp)false false false
static boolean isMirrored(int cp)false false false
static boolean isSpaceChar(int cp)false false false
static boolean isSupplementaryCodePoint(int cp)false truefalse
static boolean isTitleCase(int cp)false false false
static boolean isUnicodeIdentifierPart(int cp)true true false
static boolean isUnicodeIdentifierStart(int cp)true true false
static boolean isUpperCase(int cp)false false false
static boolean isValidCodePoint(int cp)true true true
static boolean isWhitespace(int cp)false false false
static int toLowerCase(int cp)(변경 불가능)
static int toTitleCase(int cp)(변경 불가능)
static int toUpperCase(int cp)(변경 불가능)
Character.
UnicodeBlock
Character.UnicodeBlock of(int cp)CJK_UNIFIED_IDEOGRAPHSCJK_UNIFIED_IDEOGRAPHS_EXTENSION_BHIGH_SURROGATES
Fontboolean canDisplay(int cp)(Font 인스턴스에 따라 다름)
FontMetricsint charWidth(int cp)(FontMetrics 인스턴스에 따라 다름)
문자열int indexOf(int cp)(String 인스턴스에 따라 다름)
int lastIndexOf(int cp)(String 인스턴스에 따라 다름)

기타 API

이 섹션에서는 이전 섹션에서 설명하지 않은 서로게이트 쌍 관련 API를 다룬다. 표 3은 이런 나머지 API를 전부 나타낸 것이다. 표 1, 2 또는 3에 모든 서로게이트 쌍 API가 표시되어 있다.


표 3. 기타 서로게이트 API
클래스메소드/생성자
Characterstatic int codePointAt(char[] ach, int index, int limit)
static int codePointBefore(char[] ach, int index)
static int codePointBefore(char[] ach, int index, int start)
static int codePointBefore(CharSequence seq, int index)
static int digit(int cp, int radix)
static int offsetByCodePoints(char[] ach, int start, int count, int index, int cpOffset)
static int offsetByCodePoints(CharSequence seq, int index, int cpOffset)
static char[] toChars(int cp)
static int toChars(int cp, char[] dst, int dstIndex)
문자열String(int[] acp, int offset, int count)
int indexOf(int cp, int fromIndex)
int lastIndexOf(int cp, int fromIndex)
StringBufferStringBuffer appendCodePoint(int cp)
int codePointAt(int index)
int codePointBefore(int index)
int codePointCount(int beginIndex, int endIndex)
int offsetByCodePoints(int index, int cpOffset)
StringBuilderStringBuilder appendCodePoint(int cp)
int codePointAt(int index)
int codePointBefore(int index)
int codePointCount(int beginIndex, int endIndex)
int offsetByCodePoints(int index, int cpOffset)
IllegalFormat
CodePointException
IllegalFormatCodePointException(int cp)
int getCodePoint()

목록 11은 코드 포인트에서 문자열을 작성하는 다섯 가지 방법을 나타낸 것이다. 테스트에 사용된 코드 포인트는 한 문자열에서 수십 억 번 반복된 U+53F1과 U+20B9F였다. 목록 11에서 처리 시간은 설명으로 표시된다.


목록 11. 코드 포인트에서 문자열을 작성하는 다섯 가지 방법

int cp = 0x20b9f; // CJK Ideograph Extension B
String str1 = new String(new int[]{cp}, 0, 1);    // processing time: 206ms
String str2 = new String(Character.toChars(cp));                  //  187ms
String str3 = String.valueOf(Character.toChars(cp));              //  195ms
String str4 = new StringBuilder().appendCodePoint(cp).toString(); //  269ms
String str5 = String.format("%c", cp);                            // 3781ms

str1, str2, str3str4에 대한 처리 시간이 현저히 다르지는 않다. 이들과는 달리, str5에서는 로케일 및 형식 정보를 바탕으로 유연한 출력을 지원하는 String.format()을 사용하기 때문에 작성 시간이 훨씬 더 오래 걸린다. str5 접근 방식은 프로그램의 끝 부분 근처에서 텍스트를 출력할 때만 사용해야 한다.


결론

유니코드의 모든 새 버전에서는 서로게이트 쌍으로 표시되는 새로 정의된 문자를 얻는다. 각각의 아시아 문자 세트 표준이 그런 문자의 유일한 소스는 아니다. 예를 들어, 다양한 고대 문자와 같이 휴대폰에서 이모티콘 지원도 요구된다. 이 기사에서 알게 된 기술과 성능 분석 기법은 Java 애플리케이션에서 이들을 모두 효율적으로 지원하는 데 도움이 될 것이다.


참고자료

교육

  • Unicode Consortium: 이 비영리 조직에서는 현대적 소프트웨어 제품 및 표준에서 텍스트 표시를 지정하는 유니코드 표준을 개발 및 확장하고 이 표준의 사용을 장려한다.

  • "Supplementary Characters in the Java Platform"(Norbert Lindenberg 및 Masayoshi Okutsu, java.sun.com, 2004년 5월): 유니코드 보조 문자가 Java 플랫폼에서 어떻게 지원되는지 자세히 알아보자.

  • JDK 5.0 documentation: 유니코드 서로게이트 API에 대한 공식 Javadoc를 탐색할 수 있다.

  • JSR204: Unicode Supplementary Character Support: Java 1.5에 도입된 유니코드 API는 Java 스펙 요청에서 비롯되었다.

  • International Components for Unicode (ICU): ICU는 소프트웨어 애플리케이션을 위한 유니코드 및 세계화 지원을 제공하는 라이브러리 세트이다. ICU는 IBM에서 후원, 지원 및 사용하는 오픈 소스 개발 프로젝트이다.

  • developerWorks Java 기술 영역: Java 프로그래밍과 관련된 모든 주제를 다루는 여러 편의 기사를 찾아보자.

제품 및 기술 얻기

  • 자신에게 가장한 적합한 방법으로 IBM 제품을 평가해 보자. 시험판 제품을 다운로드하거나, 온라인으로 제품을 사용해 보거나, 클라우드 환경에서 제품을 사용하거나, SOA Sandbox에서 SOA(Service Oriented Architecture)를 효과적으로 구현하는 방법을 배울 수 있다.

토론

  • My developerWorks 커뮤니티에 참여하자. 개발자가 이끌고 있는 블로그, 포럼, 그룹 및 Wiki를 살펴보면서 다른 developerWorks 사용자와 의견을 나눌 수 있다.

필자소개

Masahiko Maedera is a software engineer at the Yamato Software Development Laboratory (YSL), IBM Japan, and a member of Globalization Center of Competency. He worked on the design and implementation of string libraries in Lotus Notes/Domino.

잘못된 도움말 신고

부정사용 신고

감사합니다. 이 항목은 운영자가 관심을 표시했습니다.


잘못된 도움말 신고

부정사용 신고

제출실패 신고. 나중에 다시 실행해주세요.


디벨로퍼웍스 로그인


IBM ID가 필요하세요?
IBM ID를 잊으셨습니까?


비밀번호를 잊으셨습니까?
비밀번호 변경

developerWorks 이용 약관에 동의하시는 경우 제출을 클릭하십시오. 이용 약관.

 


developerWorks에 처음 로그인하면 developerWorks프로파일이 생성됩니다.귀하의 프로파일에서 동의하신 내용이 공개되지만 이 사항은 언제든지 변경 가능합니다. 귀하의 성명(숨김으로 체크되어 있어도 표시됩니다)과 디스플레이 이름은 게시한 컨텐츠나 사이트 엑세스시 표시됩니다.

화면상에 보여지는 닉네임을 정하세요.

처음 developerWorks에 로그인할 때 프로파일이 작성되므로, 이를 위해 디스플레이 이름을 선택해야 합니다. 선택하신 디스플레이 이름은 developerWorks에 게시한 컨텐츠에 표시됩니다.

3글자 이상 31글자 이하의 길이로 사용 가능합니다. dW커뮤니티 내에서는 보안상 이메일주소를 제외한 다른 이름을 지정하셔야 합니다.

3개의 &이나 대쉬를 포함해주시고 31글자내로 제한해주세요.


developerWorks 이용 약관에 동의하시는 경우 제출을 클릭하십시오. 이용 약관.

 


아티클 순위

의견

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=20
Zone=자바
ArticleID=591777
ArticleTitle=Java 언어를 이용한 유니코드 서로게이트 프로그래밍
publish-date=08242010
author1-email=maedera@jp.ibm.com
author1-email-cc=jaloi@us.ibm.com

태그

Help
검색 필드를 사용하여 My developerWorks 내에서 해당 태그가 사용된 모든 종류의 컨텐츠를 검색하십시오.

태그를 더 많이 보거나 적게 보기 위해 슬라이더 막대를 사용하십시오.

인기 태그는 특정 컨텐츠 존(예를 들어, 자바, 리눅스, WebSphere)의 최고 인기 태그를 보여줍니다.

내 태그는 특정 컨텐츠 존(예를 들어, 자바, 리눅스, WebSphere)의 귀하의 태그를 보여줍니다.

검색 필드를 사용하여 My developerWorks 내에서 해당 태그가 사용된 모든 종류의 컨텐츠를 검색하십시오. 인기 태그는 특정 컨텐츠 존(예를 들어, 자바, 리눅스, WebSphere)의 최고 인기 태그를 보여줍니다. 내 태그는 특정 컨텐츠 존(예를 들어, 자바, 리눅스, WebSphere)의 귀하의 태그를 보여줍니다.