본문 바로가기

Development/Java

Java에서 char 타입의 활용

 

 

char 타입의 개념

 

 

Java에서 char 타입은 Primitive type으로서, 0~65535의 정수값을 통해 16비트(2^16 = 65536)의 유니코드(Unicode) 문자를 표현한다. char 타입은 Object type인 Character 타입의 unboxed 형태이므로, Chararter 타입에 비해 활용처는 부족하지만 처리 속도가 빠르다.

 

Primitive type과 Object type의 차이에 대한 설명은 이전 글에서 다뤘다(https://hellmir.tistory.com/entry/프로그래밍에서-자료형Data-type이-필요한-이유in-Java).

 

 

프로그래밍에서 자료형(Data type)이 필요한 이유(in Java)

자료형(Data type)은 데이터를 분류하는 방법이다. 자료형을 통해 해당 자료의 처리되는 데이터 종류, 메모리 할당 과정, 연산 수행 방법을 인지할 수 있다. 예를 들어, Primitive type(기본형)인 int(정

hellmir.tistory.com

 

char 타입은 독특한 자료형인데, 정수형이지만 UTF-16이라는 인코딩 방식을 사용하여 유니코드 문자를 표현하기 때문에 이름(character)처럼 각 값에 대응하는 문자를 가지고 있다.

 

여기서 유니코드는 전 세계의 상이한 문자들을 컴퓨터를 통해 일관되게 표현하기 위한 표준 코드이다. 유니코드 값을 담은 char 타입을 통해 다양한 언어의 문자 또는 기호, 이모티콘 등을 표현하고 연산할 수 있다. 이에 따라 char 타입은 각기 언어가 다른 국가에서도 동일한 유니코드를 통해 서로의 문자를 표현할 수 있는 수단이 된다. 다만 모든 문자를 0~65535의 범위에 담을 수는 없으므로, 일부 문자는 Surrogate pair라는 인코딩 방식을 사용해서 두 개의 char값을 통해 표현해야 한다.

 

 

char 타입의 사용법

 

 

char 타입은 모든 사람들이 이해할 수 있는 숫자의 개념을 사용하기 때문에 본인이 이해할 수 없는 문자도 동일하게 사용할 수 있게 해 주며, 문자를 사칙연산을 통해 다룰 수 있으므로 익숙해지면 편리하게 활용할 수 있다. 하지만 직관적으로 익숙하지 않은 방식이기 때문에 사용법을 익히기 전에는 다루기 어려울 수 있다.

 

char c = '22'; // compile error

char 타입은 '문자열'이 아니라 '문자'를 표현하기 때문에 두 글자 이상의 문자열을 표현할 수 없다.

 

 

char 타입의 유니코드 값 확인

 

 

대부분의 사람들이 char 타입을 처음 접했을 때 가장 궁금해하는 점은 각 문자의 유니코드 값이 얼마인지에 대한 부분일 것이다. 이는 다음과 같은 과정을 통해 확인할 수 있다.

 

현재 '8'이라는 숫자의 유니코드 값을 알고 싶은 상황이다.

 

System.out.println('8'); // 8

'8'을 입력하면 8이 출력된다. 해당 문자의 유니코드 값이 아닌 대응되는 유니코드 문자를 출력하므로, 이 방법으로는 8의 유니코드 값을 알 수 없다.

 

1. Casting(강제 타입 변환)을 활용

System.out.println((int) '8'); // 56

정수형으로의 강제 타입 변환을 통해 '8'의 유니코드 값을 확인할 수 있다. '8'의 유니코드 값은 56이다.

 

byte 타입과 short 타입은 char 타입의 모든 값을 담을 수 없으므로 유의해야 한다.

 

2. Promotion(자동 타입 변환)을 활용

System.out.println('8' - 0); // 56

'8'에서 0을 빼면 역시 '8'이 가진 유니코드 값을 얻을 수 있다.

 

 

이를 이용해 다른 문자의 유니코드 값도 추출할 수 있다.

System.out.println((int) 'A'); // 65
System.out.println('A' - 0); // 65

System.out.println((int) 'a'); // 97
System.out.println('a' - 0); // 97

 

'A'의 유니코드 값이 65, 'a'의 유니코드 값이 97임을 알았으므로, 주어진 문자의 연산을 통해 대∙소문자 변환을 수행할 수 있다.

char c1 = 'A' + 32;
System.out.println(c1); // a

char c2 = 'a' - 32;
System.out.println(c2); // A

 

이는 Character 클래스의 'toLowerCase'와 'toUpperCase' 메소드를 통해서도 수행할 수 있다.

char c1 = Character.toLowerCase('A');
System.out.println(c1); // a

char c2 = Character.toUpperCase('a');
System.out.println(c2); // A

 

유니코드 값 32의 대응 문자가 ' '임을 알고 있다면 유니코드 문자 간 연산을 통해서도 수행할 수 있다.

char c1 = 'A' + ' ';
System.out.println(c1); // a

char c2 = 'a' - ' ';
System.out.println(c2); // A

 

유니코드 값을 먼저 구하지 않아도 대∙소문자 간 차이를 이용해서 수행할 수 있다.

char c1 = 'T' + 'a' - 'A';
System.out.println(c1); // t

char c2 = 't' - 'a' + 'A';
System.out.println(c2); // T

 

마찬가지 방식으로 사칙연산(+, -, *, /)의 유니코드 값도 구할 수 있다.

System.out.println('+' - 0); // 43
System.out.println('-' - 0); // 45
System.out.println('*' - 0); // 42
System.out.println('/' - 0); // 47

 

 

 

char 타입의 숫자 값 추출

 

 

char 타입 숫자의 자체 값을 통해 연산을 해야 하는 경우가 자주 있다. 숫자 값을 추출하는 방법은 유니코드 값을 추출하는 방식과 비슷하다.

 

char eight = '8';
char seven = '7';
System.out.println(eight * seven); // 3080

8과 7의 곱셉이 아니라, 8의 유니코드 값인 56과 7의 유니코드 값인 55의 곱셈이 수행되었다. 따라서 char의 숫자값들끼리의 연산을 수행하려면 문자가 아니라 유니코드 값을 8과 7로 만들어야 한다.

 

char eight = '8' - '0';
char seven = '7' - '0';
System.out.println(eight * seven); // 56

위와 같이 '8'과 '7'에서 '0'을 빼 줌으로써 유니코드 값 8과 7을 만들면 숫자 자체 값끼리의 연산을 수행할 수 있다.

 

 

char 타입의 활용

 

 

문자열을 배열로 변경

 

 

문자열을 문자 배열로 분할하는 작업은 split 메소드를 통해서도 수행할 수 있지만, toCharArray 메소드를 활용하면 char 타입 문자의 배열로도 만들 수 있다.

String str = "abcde";
char[] array = str.toCharArray(); //배열로 변경
System.out.println(Arrays.toString(array)); // [a, b, c, d, e]

 

이 방법이 split 메소드보다 편리한 이유는 문자열을 for each 반복문에서 바로 연산할 수 있기 때문이다.

String str = "abcde";

for (char c : str.toCharArray()) {
    System.out.printf("%c ", c); // a b c d e
}

반복 수행마다 char 타입의 문자가 주어지므로, 개별 문자의 연산을 편리하게 수행할 수 있다.

 

 

문자열을 List, Set, Map으로 변경

 

 

String str = "abcdabcaba";

List<Character> list = new ArrayList<>();

for(char c : str.toCharArray()) {
    list.add(c); // List로 변경
}

System.out.println(list); // [a, b, c, d, a, b, c, a, b, a]

Set<Character> set = new HashSet<>();

for (char c : str.toCharArray()) {
    set.add(c); // Set으로 변경
}

System.out.println(set); // [a, b, c, d]

Map<Character, Character> map = new HashMap<>();

for(char c : str.toCharArray()) {
    map.put((char) (c - ' '), c); // 키에 c - ' ', 값에 c를 대입
}

System.out.println(map); // {A=a, B=b, C=c, D=d}

toCharArray 메소드와 for each 반복문을 활용해 List, Set, Map의 형태로도 간편하게 변환할 수 있다. Stream을 이용하지 않아도 되기 때문에 구 버전 Java의 사용자도 쉽게 사용 가능한 방법이다.

 

Map은 이를 응용하여 문자열에 포함된 각 문자들의 중복 횟수를 연산할 수 있다.

String str = "abcdabcaba";

Map<Character, Integer> map = new HashMap<>();

for (char c : str.toCharArray()) {
    map.put(c, map.getOrDefault(c, 0) + 1); // 키에 c, 값에 키 c의 값 + 1의 값을 대입, 없으면 1을 대입
}

for (char key : map.keySet()) {
    System.out.printf("%c의 개수: %d\n", key, map.get(key));
}
/*
a의 개수: 4
b의 개수: 3
c의 개수: 2
d의 개수: 1
*/

toCharArray 메소드를 통해 각 문자들의 개수 정보를 간편하게 계산, 저장할 수 있어 유용하다.