프로그래머스 입문 120893 대문자와 소문자
문제
문자열은 영어 알파벳 대문자와 소문자로 이루어져 있다.
대문자는 소문자로, 소문자는 대문자로 변환해서 문자열을 반환하시오.
| my_string | result |
|---|---|
| “cccCCC” | “CCCccc” |
| “abCdEfghIJ” | “ABcDeFGHij” |
풀이
영어 알파벳에서 같은 문자의 대문자와 소문자는 ASCII 값을 10진수로 보면 32만큼 차이가 난다.
'A'(65) ↔'a'(97)'B'(66) ↔'b'(98)
이 차이는 비트로 보면 더 명확하다.
'A' = 0100 0001
'a' = 0110 0001
↑ (0x20 = 32)
이 성질을 이용하면 아래와 같은 방법들로 문제를 풀 수 있다.
XOR
#include <stdlib.h>
#include <string.h>
char* solution(const char* my_string)
{
size_t len = strlen(my_string);
char* result = malloc(len + 1);
for (size_t i = 0; i < len; i++)
{
result[i] = my_string[i] ^ 0x20;
}
result[len] = '\0';
return result;
}
문자열이 영어 대문자와 소문자로만 이루어져 있으므로 별도의 검증 없이 XOR 연산으로 5번 비트만 토글한다.
여기서 5번 비트는 오른쪽에서 여섯 번째 비트를 뜻한다.
대문자는 이 비트가 꺼져 있으므로 토글하면 켜지면서 소문자가 되고, 소문자는 이 비트가 켜져 있으므로 토글하면 꺼지면서 대문자가 된다.
0x20 대신 32나 (1 << 5)를 사용해도 같은 동작을 한다.
ASCII 차이
#include <stdlib.h>
#include <string.h>
char* solution(const char* my_string)
{
size_t len = strlen(my_string);
char* result = malloc(len + 1);
for (size_t i = 0; i < len; i++)
{
if (my_string[i] >= 'A' && my_string[i] <= 'Z')
{
result[i] = my_string[i] + 32;
}
else
{
result[i] = my_string[i] - 32;
}
}
result[len] = '\0';
return result;
}
영어 대문자와 소문자의 ASCII 값은 32만큼 차이가 난다.
따라서 XOR를 사용하지 않고, 대문자에는 32를 더하고 소문자에는 32를 빼는 방식으로도 구현할 수 있다.
문자 기준
#include <stdlib.h>
#include <string.h>
char* solution(const char* my_string)
{
size_t len = strlen(my_string);
char* result = malloc(len + 1);
for (size_t i = 0; i < len; i++)
{
if (my_string[i] >= 'A' && my_string[i] <= 'Z')
{
result[i] = my_string[i] - 'A' + 'a';
}
else
{
result[i] = my_string[i] - 'a' + 'A';
}
}
result[len] = '\0';
return result;
}
ASCII 값 차이를 알고 있으면 앞선 풀이들을 바로 이해할 수 있지만, 그렇지 않다면 32나 0x20은 매직 넘버처럼 보일 수 있다.
정수 리터럴 대신 기준 문자를 사용하면, 각 문자를 알파벳에서의 위치 값으로 바꾼 뒤 반대쪽 대소문자의 시작 문자에 더한다는 의도가 드러난다.
영어 알파벳은 26글자이므로 대문자에서 'A'를 빼면 0부터 25까지의 위치 값이 나오고, 여기에 'a'를 더하면 같은 위치의 소문자가 된다.
반대로 소문자에서도 'a'를 빼면 0부터 25까지의 위치 값이 나오고, 여기에 'A'를 더하면 같은 위치의 대문자가 된다.
표준 라이브러리 사용
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
char* solution(const char* my_string)
{
size_t len = strlen(my_string);
char* result = malloc(len + 1);
for (size_t i = 0; i < len; i++)
{
result[i] = isupper(my_string[i]) ? tolower(my_string[i]) : toupper(my_string[i]);
}
result[len] = '\0';
return result;
}