(연습문제) 대소문자변환

연습문제 : 대소문자 변환하기

입력받은 문자열의 대소문자를 반전하여 출력하는 프로그램을 작성하시오.

입력받은 각 글자의 문자 코드가 ‘a’ … ‘z’ 사이에 있으면 소문자, ‘A’~’Z’ 사이에 있으면 대문자이다. 그리고 그 변환은 해당 코드값에 a - A를 더하거나 빼주면 된다.

먼저 대소문자의 범위를 찾아보자.

print("azAZ".utf8.map(Int.init))
//=> [97, 122, 65, 90]

즉 문자 코드가 97~122 구간에 있으면 소문자, 65~90 구간에 있으면 대문자이다. 소문자->대문자 변환은 32를 빼고, 반대의 변환은 32를 더한다.

문자 코드 값으로 다시 문자를 만드는 방법은 다음과 같다.

  1. 문자열은 [Character] 타입으로 만들 수 있다.
  2. 코드값으로 Character 인스턴스를 만들기 위해서는 Int 값을 UnicodeScalar 값으로 변환하면 된다.

즉, 다음과 같이 변경할 수 있다.

let arr = [97, 122, 65, 90]
let str = String(arr.map{ Character(UnicodeScalar($0)) })
print(str)
//=> "azAZ"

전체 코드는 다음과 같다.

if let s = readLine(), case let u = s.utf8.map(Int.init) {
    let h: Int -> Int = { n in
        switch n {
        case 97...122: return n - 32
        case 65...96: return n + 32
        default: return n
        }
    }
    let result = String(u.map{ Character(UnicodeScalar(h($0))) })
    print(result)
}

위의 switch 문은 간단히 삼항 연산자의 중첩으로 쓸 수 있다. 범위(Range<Int>)에 특정 값이 있는지는 패턴매칭으로 찾는데, 패턴매칭은 연산자 ~=를 쓰므로 다음과 같이 코드를 줄일 수 있다.

/* shorter version */
if let s = readLine(), case let u = s.utf8.map(Int.init) {
    let h: Int -> Int = { n in return 97...122 ~= n ? n - 32 : 65...96 ~= n ? n + 32 : n }
    let result = String(u.map{ Character(UnicodeScalar(h($0))) })
    print(result)
}

하스켈 풀이

하스켈의 경우, Data.Char 모듈에 isUpper, toUpper, toLower 함수가 정의되어 있으므로 이를 이용할 수 있다.

import Data.Char
main = interact (map f) where f c = if isUpper c then toLower c else toUpperc

interact 함수는 String -> String -> IO () 타입의 함수로 입력받은 문자열을 처리해주는 함수를 받아서 입력과 출력을 연결해주는 함수이다. 즉,

main = getLine >= (\xs -> putStrLn . (map f) $ xs)

를 줄인 것이다.