Algorithm/Programmers

[Programmers] JadenCase 문자열 만들기

j4ko 2023. 2. 9. 23:27
728x90
반응형

 

JadenCase란 모든 단어의 첫 문자가 대문자이고, 그 외의 알파벳은 소문자인 문자열입니다. 단, 첫 문자가 알파벳이 아닐 때에는 이어지는 알파벳은 소문자로 쓰면 됩니다. (첫 번째 입출력 예 참고)문자열 s가 주어졌을 때, s를 JadenCase로 바꾼 문자열을 리턴하는 함수, solution을 완성해주세요.

제한 조건
s는 길이 1 이상 200 이하인 문자열입니다.
s는 알파벳과 숫자, 공백문자(" ")로 이루어져 있습니다.
- 숫자는 단어의 첫 문자로만 나옵니다.
- 숫자로만 이루어진 단어는 없습니다.
- 공백문자가 연속해서 나올 수 있습니다.


개요

이 문제는 조건을 명확히 인지하고 문제에서 주어진 케이스 외의 경우를 잘 고민해봐야 하는 문제였다. "이게 아니라고?"라는 생각에 힌트를 보고 풀긴 했다. 

Solve

입출력 예시에 대한 설명은 어렵지 않았으므로 문제를 읽고 풀이 순서를 다음과 같이 세웠다.

1. 문장을 공백을 기준으로 나눈다. 문장을 이루는 단어가 나온다.
2. 각 단어의 시작 문자를 체크하며 다음과 같은 경우로 나눈다.
  2-1.  시작 글자가 알파벳이고 소문자인 경우 대문자로 치환하고 나머지 문자는 소문자로 대체한다.
  2-2. 시작 글자가 알파벳이 아닌 경우 나머지 문자를 소문자로 대체한다.

처음엔 코드를 다음과 같이 짰다.

# 1st try..
def solution(s):
    tokens = s.split(" ")
    answer = []
    
    for idx, token in enumerate(tokens):
        if token == '':
            answer.append("")

        if token != '':
            start_char = token[0:1]
            suffix_chars = token[1::]

            if start_char.isalpha() and start_char.islower():
                answer.append(start_char.upper() + suffix_chars.lower())
    
            if not start_char.isalpha():
                answer.append(start_char + suffix_chars.lower())

    return " ".join(answer)

단어(token)가 공백이 아닐 경우의 흐름은 다음과 같다.

  • 공백으로 나눈 집합에서 각 단어(token)를 시작 문자(start_char)와 나머지 문자(suffix_chars)를 각각 변수에 저장해 둔다.
    • 시작 문자가 알파벳이며 소문자인 경우 시작 문자를 대문자로 변경하며 나머지 문자열을 더해 답으로 제출할 answer 변수에 따로 담아둔다.
    • 시작 문자가 알파벳이 아닌 경우 미리 나눠놓은 나머지 문자(suffix_chars)를 더해 answer 변수에 담는다. 


그런데 위 코드는 정답이 아니다. 위 코드로  실패하여 머리가 복잡했는데 짜놓은 코드를 한 두시간 정도 지나고 보니 중복된 의미를 지닌 표현이 보여 이를 다음과 같이 고쳤다.

def solution(s):
    tokens = s.split(" ")

    answer = []

    for idx, token in enumerate(tokens):

        if token == '':
            answer.append("")
        else:
            start_char = token[0:1]
            suffix_chars = token[1:]

            if start_char.isalpha():
                answer.append(start_char.upper() + suffix_chars.lower())
            else:
                answer.append(start_char + suffix_chars.lower())

    return " ".join(answer)

고친 후의 흐름은 다음과 같다.

  • 시작 문자가 알파벳인 경우, 시작 문자를 대문자로 처리하고 나머지 문자를 소문자로 처리한 후  answer에 담는다. 
  • 시작 문자가 알파벳이 아닌 경우, 시작 문자는 그대로 두고 나머지 문자열을 소문자로 처리해서 담는다.

 

사실은 capitalize...

문제를 풀고서 다른 풀이 방법은 뭐가 있나 보게 됐는데 capitalize() 함수를 사용하면 된다는 것을 알 수 있었다. 파이썬에 내장된 문자열 함수기도 한  capitalize 함수는 문제에서 요구한 동작을 정확히 수행하는 함수다. 이를 적용한 코드의 형태는 다음과 같다.

def solution(s):
    tokens = s.split(" ")

    answer = []

    for idx, token in enumerate(tokens):
        if token == '':
            answer.append("")
        else:
            answer.append(token.capitalize())

    return " ".join(answer)

코드가 더 간결해졌으며 결과는 다음과 같다.

문제에서 요구하는 동작을 일일이 구현해 처리한 방식은 0.01 ~ 0.02로 왔다 갔다 했는데 0.01로 일정하다.

 

Notes

문제를 풀 때 두 가지 포인트를 놓쳤었다. 하나는 입력한 값 그대로 다시 결과가 나와야 했다는 점이다. 즉, 문제에서 요구하는 "공백문자가 연속해서 나올 수 있습니다"에 대한 의미를 정확히 인지하지 못한 것이었다. 그래서 이 문제를 풀 때 다음과 같이 테스트 케이스를 unittest로 정해두고 풀어나갔다.

class TestCase(unittest.TestCase):

    def test_example01(self):
        example = "3people unFollowed me"
        result = "3people Unfollowed Me"

        self.assertEqual(solution(example), result)

    def test_example02(self):
        example = "for the last week"
        result = "For The Last Week"

        self.assertEqual(solution(example), result)

    def test_example03(self):
        example = "  ze  ze  ze  ze"
        result = "  Ze  Ze  Ze  Ze"
        self.assertEqual(solution(example), result)

    def test_example04(self):
        example = "  ze  "
        result = "  Ze  "
        self.assertEqual(solution(example), result)

나머지 하나는 split() 메서드에 대한 오해다. 

example = "a b c"
print(example.split())
print(example.split(" "))

위는 그냥 split를 쓰고 아래는 split을 쓸 때 공백 문자로 자르는 것이다. 위 예제의 결과를 보면 다음과 같이 차이가 없다.

['a', 'b', 'c']
['a', 'b', 'c']

그런데 문자열에 공백이 포함되는 경우는 출력이 달라진다.

example = " a b c "

위와 같이 양쪽에 공백이 포함되는 경우는 다음과 같이 출력된다.

['a', 'b', 'c']
['', 'a', 'b', 'c', '']

 

728x90
반응형