🔄 루비 문자열 최종장: slice(추출), to_i/to_f(숫자변환), concat(원본결합) 정복!

🎯 이번 시간 학습 목표

드디어 루비 문자열 다루기 시리즈의 마지막 시간입니다! 🎉 지난 시간까지 문자열을 나누고(split) 바꾸는(gsub/sub) 강력한 편집 기술을 익혔죠. 오늘은 문자열 여정을 마무리하며, 더욱 섬세한 추출, 타입 변환, 그리고 원본을 직접 수정하는 결합 방법을 마스터해 보겠습니다!

  • slice: 문자열의 특정 부분을 정교하게 추출하는 또 다른 방법 배우기
  • to_i / to_f: 문자열로 표현된 숫자를 실제 정수(Integer)실수(Float) 타입으로 변환하기
  • concat (또는 <<): 기존 문자열에 다른 문자열을 직접 이어 붙여 원본을 변경하기

이 기술들은 문자열 데이터를 최종적으로 활용 가능한 형태로 만들거나, 효율적인 문자열 조작이 필요할 때 유용하게 사용됩니다. 문자열 마스터를 향한 마지막 스퍼트, 함께 달려봅시다! 🚀

✨ 오늘 배울 내용 미리보기

함수/메소드 설명 간단 예시
slice(index)
slice(start, length)
slice(range)
slice(substring)
문자열의 특정 부분을 추출하여 새로운 문자열로 반환합니다. []와 유사하게 동작합니다. "ruby".slice(1..2)"ub"
"ruby".slice(1, 2)"ub"
to_i(base=10) 문자열을 해석하여 정수(Integer)로 변환합니다. base로 진법을 지정할 수 있습니다. "123".to_i123
"101".to_i(2)5
to_f 문자열을 해석하여 부동소수점 실수(Float)로 변환합니다. "3.14".to_f3.14
concat(other_str)
<<(other_str)
other_str원본 문자열 뒤에 직접 이어 붙여 원본 자체를 변경합니다. (파괴적 메소드) a = "hi"; a.concat(" ruby")a"hi ruby"가 됨

📌 slice[]와 매우 유사하며, concat<<는 원본을 변경한다는 점이 중요합니다! 아래에서 자세히 알아볼게요.


🔪 정교하게 잘라내기! `slice`

지난 시간에 배운 대괄호 인덱싱([]) 기억하시나요? slice 메소드는 그와 거의 동일한 기능을 제공하며, 문자열의 특정 부분을 잘라내어 '새로운' 문자열로 반환합니다. 사용법도 매우 유사합니다!

[]와 마찬가지로 다양한 형태로 인자를 전달할 수 있습니다:

  • `slice(index)`: 해당 인덱스의 글자 하나를 반환합니다. (0부터 시작, 음수 가능)
  • `slice(start, length)`: `start` 인덱스부터 `length` 길이만큼의 부분 문자열을 반환합니다.
  • `slice(range)`: 주어진 범위(`..` 또는 `...`)에 해당하는 부분 문자열을 반환합니다.
  • `slice(substring)`: 문자열 내에서 `substring`과 일치하는 첫 번째 부분을 찾아 반환합니다. (찾는 문자열이 없으면 nil)
  • `slice(regexp)`: 정규표현식과 일치하는 첫 번째 부분을 찾아 반환합니다. (찾는 내용이 없으면 nil)
message = "Welcome to Ruby World!"

# index 사용
puts message.slice(0)    # 출력 결과: "W"
puts message.slice(-1)   # 출력 결과: "!"

# start, length 사용
puts message.slice(8, 2) # 출력 결과: "to" (8번째부터 2글자)

# range 사용
puts message.slice(11..14) # 출력 결과: "Ruby" (11번째부터 14번째까지)

# substring 사용
puts message.slice("Ruby") # 출력 결과: "Ruby"
puts message.slice("Java") # 출력 결과: nil (찾는 문자열 없음)

# regexp 사용 (예: 첫 번째 단어 찾기)
puts message.slice(/\w+/) # 출력 결과: "Welcome"

💡 Tip: 사실 루비에서 문자열의 slice 메소드와 [] 연산자는 대부분의 경우 동일하게 작동하는 '별칭(alias)' 관계입니다. 어떤 것을 사용해도 괜찮지만, 메소드 호출임을 명확히 하고 싶을 때 slice를 사용하기도 합니다.

❗ 원본 변경 버전: `slice!`

만약 문자열에서 특정 부분을 '잘라내고 그 부분만 결과로 얻는' 동시에 **원본 문자열에서도 해당 부분을 제거**하고 싶다면, 파괴적인(destructive) `slice!` 메소드를 사용합니다. 잘려나간 부분이 반환되고, 원본 문자열은 그 부분이 제거된 상태로 변경됩니다.

my_string = "HelloRuby"
extracted = my_string.slice!(5..8) # 5~8 인덱스 부분을 잘라냄

puts extracted  # 출력 결과: "Ruby" (잘려나간 부분)
puts my_string  # 출력 결과: "Hello" (원본에서 해당 부분이 제거됨)

slice!는 원본을 직접 수정하므로 주의해서 사용해야 합니다!


🔢 문자열, 숫자로 변신! `to_i` & `to_f`

웹사이트 입력, 파일 읽기 등으로 얻은 데이터는 종종 문자열 형태입니다. "100"이나 "3.14" 같은 문자열을 실제 숫자 계산에 사용하려면 숫자 타입(Integer 또는 Float)으로 변환해야 하죠. 이때 to_ito_f가 마법을 부립니다! ✨

정수로 변환: `to_i` (to Integer)

to_i는 문자열의 **시작 부분부터** 숫자로 해석될 수 있는 부분까지 읽어서 정수(Integer)로 변환합니다. 숫자가 아닌 문자를 만나면 그 즉시 해석을 멈춥니다.

puts "123".to_i       # 출력 결과: 123
puts "99 red balloons".to_i # 출력 결과: 99 (숫자 아닌 ' ' 만나서 멈춤)
puts "Age: 25".to_i    # 출력 결과: 0 (숫자로 시작하지 않음)
puts "-100".to_i      # 출력 결과: -100 (음수도 가능)
puts "1_000_000".to_i # 출력 결과: 1000000 (밑줄은 무시됨)
puts "  777  ".to_i   # 출력 결과: 777 (앞뒤 공백 무시)

진법 변환 (Base Conversion): to_i는 선택적으로 '진법(base)'을 인자로 받습니다. 2부터 36까지 가능하며, 기본값은 10진법입니다.

puts "101".to_i(2)   # 출력 결과: 5 (2진법 "101"을 10진법으로)
puts "ff".to_i(16)   # 출력 결과: 255 (16진법 "ff"를 10진법으로)
puts "10".to_i(8)    # 출력 결과: 8 (8진법 "10"을 10진법으로)

실수로 변환: `to_f` (to Float)

to_f는 문자열을 부동소수점 실수(Float)로 변환합니다. to_i와 유사하게 동작하지만, 소수점(.)과 지수 표현(e 또는 E)까지 인식합니다.

puts "3.14159".to_f    # 출력 결과: 3.14159
puts "100".to_f        # 출력 결과: 100.0 (정수도 실수로 변환)
puts "-0.5".to_f       # 출력 결과: -0.5
puts "1.23e2".to_f     # 출력 결과: 123.0 (지수 표현 1.23 * 10^2)
puts "PI = 3.14".to_f  # 출력 결과: 0.0 (숫자로 시작하지 않음)
puts "  -99.9  ".to_f # 출력 결과: -99.9 (앞뒤 공백 무시)
🤔 숫자로 바꿀 수 없는 문자열은 어떻게 되나요?
문자열의 시작 부분이 숫자로 해석될 수 없다면, to_i0을, to_f0.0을 반환합니다. 오류가 발생하는 것이 아니라 기본값을 반환한다는 점에 유의하세요! 만약 엄격하게 숫자 형식만 허용하고 싶다면, 정규표현식 등으로 미리 문자열 형식을 검사하는 로직이 필요할 수 있습니다.

🔗 원본에 착! 붙여넣기! `concat` 또는 `<<`

우리는 이전에 + 연산자를 사용해 문자열을 합치는 법을 배웠습니다. +는 두 문자열을 합쳐 '새로운' 문자열 객체를 만들었죠. 하지만 때로는 기존 문자열 객체 자체에 다른 문자열을 이어 붙여 원본을 변경하고 싶을 때가 있습니다. 이때 concat 또는 그 별칭인 << 연산자를 사용합니다. 이들은 **파괴적(destructive)**으로 동작합니다!

greeting = "Hello"

# concat 사용
greeting.concat(" World")
puts greeting # 출력 결과: "Hello World" (greeting 변수 자체가 변경됨)

# << 사용 (concat과 동일하게 동작)
greeting << "!"
puts greeting # 출력 결과: "Hello World!" (greeting 변수에 "!"가 추가됨)

# 여러 번 이어 붙이기
message = "Ruby "
message << "is " << "fun" << "!"
puts message # 출력 결과: "Ruby is fun!"

⚡️ `+` 와 `concat`/`<<` 의 차이점 비교

str1 = "abc"
str2 = str1

# + 연산자: 새로운 객체 생성
str3 = str1 + "def"
puts str1.object_id  # 객체 ID (예: 701...)
puts str2.object_id  # 객체 ID (str1과 동일)
puts str3.object_id  # 객체 ID (str1, str2와 다름!)

# concat/<< 연산자: 원본 객체 변경
str1.concat("ghi") # 또는 str1 << "ghi"
puts str1.object_id  # 객체 ID (위의 str1과 동일!)
puts str2.object_id  # 객체 ID (str1과 동일! str2도 함께 변경됨)
puts str1          # 출력 결과: "abcghi"
puts str2          # 출력 결과: "abcghi"

위 예제처럼 +는 새로운 객체를 만들지만, concat이나 <<는 원본 객체를 직접 수정합니다. 따라서 같은 객체를 참조하는 다른 변수(str2)에도 변경 사항이 반영됩니다. 메모리 사용 측면에서는 concat/<<가 새 객체를 만들지 않아 더 효율적일 수 있지만, 원본 변경으로 인한 예기치 못한 부작용(side effect)이 발생할 수 있으므로 상황에 맞게 주의해서 사용해야 합니다.


✨ 루비 문자열 여정, 성공적으로 완주! ✨

정말 수고 많으셨습니다! 🎉 이로써 루비 문자열 다루기의 기본 여정을 모두 마쳤습니다. 우리는 문자열의 길이를 재고, 내용을 검색하고, 대소문자를 바꾸고, 공백을 제거하고, 쪼개고, 바꾸고, 추출하고, 숫자로 변환하고, 심지어 원본을 직접 수정하며 이어 붙이는 등 다양한 기술들을 배웠습니다!

length, empty?, +, upcase, downcase, strip, include?, start_with?, end_with?, [], split, gsub, sub, 그리고 오늘 배운 slice, to_i, to_f, concat 까지! 이 강력한 도구들을 자유자재로 활용하여 여러분의 루비 코드를 더욱 풍성하고 효율적으로 만들어보세요.

다음 시리즈에서는 루비의 또 다른 핵심 데이터 타입인 **숫자(Number)**와 다양한 **수학 연산**에 대해 깊이 알아보는 시간을 갖겠습니다. 더욱 흥미진진한 루비의 세계로 함께 떠날 준비, 되셨나요? 😉 기대해주세요!