오늘은 문자열 변환 관련 메서드 중 몇 가지를 살펴보는 것부터 시작해 보겠다.
우선 대소문자 변환 메서드를 보면, upcase 메서드는 대문자로 변환해 주고, downcase 메서드는 소문자로 변환해 준다.
그리고 swapcase 메서드는 소문자는 대문자로, 대문자는 소문자로 변환해 준다.
마지막으로 capitalize 메서드는 첫 번째 문자를 대문자로, 나머지 문자들은 모두 소문자로 변환해 준다.
그리고 String 클래스에는 대상 문자열 자체를 변경하는 upcase!, downcase!, swapcase!, capitalize! 메서드들도 가지고 있다.
아래 그림을 보면 어떤 기능을 하는 메서드인지 쉽게 알 수 있다.
아래는 capitalize 메서드를 사용하여 문장에 등장하는 모든 단어들의 첫 번째 글자들만 대문자로 변경하는 간단한 코드를 작성해 봤다.
그런데, 두 번째 코드를 보면 map 메서드에 인수로 &:capitalize 를 전달하고 있는데, 이 것은 블록을 받는 메서드에 블록을 (인수로서) 전달하는 방법 중 하나이다.
내부적으로 심볼 객체(:capitalize)의 to_proc 메서드가 호출되고, 결과로 받은 Proc 객체가 앞에 붙인 &을 통해 블록으로 전달되게 된다.
심볼 객체의 to_proc 메서드는 블록 파라미터로 받은 객체에 대해 심볼 자신과 동일한 이름의 메서드를 호출하는 Proc 객체를 생성해서 반환하도록 구현되어 있다.
아래 그림을 보면 MySymbol 이라는 클래스를 하나 정의했는데, 그 안에 to_proc 메서드를 앞서 얘기한 심볼의 to_proc 메서드처럼 동작하도록 만들어 봤다.
그리고 "capitalize" 를 인수로 하여 MySymbol 객체를 생성하여 변수 cap에 할당하고, 배열의 map 메서드를 &cap 과 함께 호출하였다.
그 다음은 배열 요소에 대해 length 메서드를 호출하도록 MySymbol 객체를 생성하고 map 메서드에 전달했다.
다음으로, 문자열에서 특정 문자를 삭제하는 메서드를 알아보자.
아래 그림을 보면 delete 메서드가 보이는데 delete 메서드는 대상 문자열에서 인수로 받은 문자열 안의 문자들을 모두 제거한다.
그런데, 두 번째 예제처럼 인수가 두 개 이상일 때는 인수로 받은 모든 문자열에서 공통으로 포함된 문자들만 제거한다.
따라서 두 번째 delete 예제에서는 인수로 건넨 두 문자열 "us" 와 "is" 에서 겹치는 문자인 's' 만 대상 문자열에서 제거된다.
delete 메서드는 해당 문자들이 제거된 새로운 문자열을 생성해서 돌려주지만 delete! 메서드는 대상 문자열 자체를 변경한다.
그리고, delete 메서드처럼 문자열에서 특정 문자를 제거하는 기능을 갖고 있지만 성격이 조금 다른 chop 메서드와 chomp 메서드가 있다.
우선 'chop' 과 'chomp' 이라는 영어 단어가 무슨 뜻인지 이전에 만들었던 단어 검색기 프로그램을 사용하여 확인해 보자.
'chop'이라는 단어의 뜻에서 동의어 'cut' 이 실제 chop 메서드의 기능을 설명해 줄 수 있는 의미를 담고 있다고 생각이 되는데, 실제 chop 메서드는 문자열의 가장 마지막 문자 하나를 잘라버린다!
'chomp'은 '쩝쩝 먹다'라는 의미가 어울릴 수도 있겠다. 피자나 빵을 손에 쥐고 끝에서부터 먹는 모습을 생각하면 된다. 여기서는 실제 피자나 빵이 아니라 문자열이고 chomp 메서드는 문자열의 끝에서 특정 문자들을 먹어 없앤다.
인수를 주지 않으면 chomp 메서드는 문자열 끝에 있는 개행 문자 하나를 제거해 주는데, 유닉스 계열의 운영체제라면 "\n"(Line Feed)를, 윈도우즈라면 "\r\n"(Carriage Return + Line Feed)를 개행 문자로 사용한다.
만약 인수로 빈문자열("")을 주게 되면 문자열 끝에 오는 모든 개행 문자들을 제거해 준다. 그리고 빈 문자열이 아닌 문자열을 인수로 주면 해당 문자열을 대상 문자열의 끝에서 찾아 없애준다.
아래 그림을 보면 대상 문자열 "Ruby!!" 에 대해 chomp("!") 을 호출하면 대상 문자열의 끝에 있는 느낌표 하나만 제거되고, chomp("!!") 을 호출하면 두 개 모두 제거 되지만, chomp("!!!") 을 호출하면 하나도 제거되지 않는 걸 볼 수 있다.
즉, 대상 문자열 끝에서 인수로 건넨 문자열과 정확히 일치하는 부분을 한 번만 제거한다.
그리고, String 클래스에는 대상 문자열 자체를 변경하는 chop! 과 chomp! 메서드도 존재한다.
특히, 문자열의 앞 또는 끝, 혹은 앞과 끝에 붙어 있는 모든 공백 문자들을 한 번에 제거 하고 싶다면 lstrip, rstrip, strip 메서드를 사용하면 된다.
lstrip 메서드는 문자열의 앞에 있는 모든 공백 문자들을 제거해 주고, rstrip 메서드는 문자열의 끝에 붙은 모든 공백 문자들을 제거해 준다.
그리고 strip 메서드는 문자열의 앞과 끝에 있는 모든 공백 문자들을 제거해 준다.
여기서 말하는 공백 문자("\s")는 말 그대로 공백 문자(" ")와 개행 문자("\n", "\r") 그리고 탭 문자("\t") 등을 포함한다.
아래 그림의 마지막 예제를 보면 'Ruby' 뒤에 공백 문자가 아닌 '!' 가 있어 뒤쪽에서는 '!' 다음에 오는 공백 문자들만 제거 된 걸 볼 수 있다.
대상 문자열 자체를 변경하는 lstrip!, rstrip! strip! 메서드도 존재한다.
다음으로 문자열을 좌우, 가운데로 정렬해 주는 메서드를 살펴보자.
아래 그림을 보면 ljust 메서드는 왼쪽(left)으로 정렬된 문자열을 돌려주고, rjust 메서드는 오른쪽(right)으로 정렬된 문자열을 돌려주며, center 메서드는 가운데로 정렬된 문자열을 돌려준다.
세 메서드 모두 인수를 두 개 받는데, 대상 문자열을 첫 번째 인수로 건넨 길이에 맞추되, 남는 부분은 두 번째 인수로 건넨 문자열로 채운다. 만약, 두 번째 인수를 생략하면 공백 문자로 채우게 된다.
'문자열과 친해지기' 첫 번째 글의 length 메서드와 size 메서드 부분에서 설명한 것처럼, 한글 문자 하나의 길이는 1이지만 바이트 크기는 인코딩에 따라 2 또는 3일 수 있다.
ljust, rjust, center 메서드 모두 문자열의 length 와 첫 번째 인수의 값을 비교하여 정렬을 하는데, 화면 상에서 영어 알파벳 또는 아라비아 숫자 하나의 폭이 한글 문자 하나의 폭과 다르다.
따라서, 한글과 영어 알파벳 등이 함께 포함되어 있는 문자열을 화면에 보기 좋게 정렬해서 출력하기 위해서는 약간의 작업이 필요한데, 이것과 관련해서는 '데이터 정렬해서 출력하기' 글을 참고하길 바란다.
아래 center 메서드를 사용하여 간단하게 피라미드를 그려보았다.
다음은 문자열을 특정 문자열을 구분자로 하여 나누는 split 메서드를 살펴보자.
인수 없이 split 메서드를 호출하면 대상 문자열을 앞서 strip 메서드에서 말한 공백 문자("\s")를 기준으로 문자열을 나누게 되는데, 이때 공백 문자가 어느 위치에 몇 개가 오든 상관 없이, 공백 문자가 아닌 문자열들만 배열에 담아 돌려준다.
그리고 구분자로 사용할 문자열을 첫 번째 인수로 주고 split 메서드를 호출하게 되면, 그 구분자를 기준으로 문자열을 나눠서 배열로 돌려준다.
이때 주의할 것은 아래 그림에서 보이듯이 구분자가 문자열의 앞 또는 끝에 오거나 중간에 연달아 올 경우, 끝에 오는 구분자 사이의 빈 문자열("")은 결과 배열에 포함되지 않는다는 것이다.
split 메서드는 두 번째 인수로 대상 문자열을 몇 개로 나눌지를 지정할 수가 있는데, -1 을 주면 끝에 오는 구분자 사이의 빈 문자열("")도 결과 배열에 포함시킬 수 있다.
프로그래밍 언어들마다 프로그램 작성 편의를 위해 기본적으로 많은 기능들을 제공하고 있는데, split 메서드 역시 Java, Python, Javascript 등의 언어에서 기본으로 제공하고 있다.
그런데, 'split' 이라는 이름까지 같지만 동작 방식은 서로 조금씩 다른데, Java는 Ruby와 동작 방식이 같고 Python과 Javascript는 Ruby에서 두 번째 인수에 -1을 줬을 때와 동일하게 동작한다.
'split' 뿐만 아니라 다른 기능들에서도 언어들마다 차이가 있을 수 있으므로, 여러 프로그래밍 언어를 사용하여 개발을 할 때는 가정하지 말고 테스트를 통해 확인하는 습관을 들이는 게 좋다.
다음 글에서는 문자열에서 특정 문자열을 검색하는 기능들부터 살펴보겠다.
See you again~~