연습문제 : 대소문자 변환하기
입력받은 문자열의 대소문자를 반전하여 출력하는 프로그램을 작성하시오.
입력받은 각 글자의 문자 코드가 ‘a’ … ‘z’ 사이에 있으면 소문자, ‘A’~’Z’ 사이에 있으면 대문자이다. 그리고 그 변환은 해당 코드값에 a - A
를 더하거나 빼주면 된다.
먼저 대소문자의 범위를 찾아보자.
print("azAZ".utf8.map(Int.init))
//=> [97, 122, 65, 90]
즉 문자 코드가 97~122 구간에 있으면 소문자, 65~90 구간에 있으면 대문자이다. 소문자->대문자 변환은 32를 빼고, 반대의 변환은 32를 더한다.
문자 코드 값으로 다시 문자를 만드는 방법은 다음과 같다.
- 문자열은
[Character]
타입으로 만들 수 있다. - 코드값으로
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)
를 줄인 것이다.