(본 게시물은 저작권의 문제 발생시 출판사의 요청에 의해 삭제될 수 있습니다.)
문자열
루비 문자열은 간단히 말하면 문자열 시퀀스다. 보통 출력가능한 문자를 저장하지만 반드시 그래야만 하는 것은 아니다. 문자열에는 이진(binary) 데이터를 저장할 수도 있다. 문자열은 String 클래스의 객체다.
큰따옴표로 묶인 문자열은 많은 이스케이프 시퀀스를 지원한다. 그 중 가장 일반적인 것이 줄바꿈을 나타내는 \n 이다. 또한 #{ expr } 과 같은 식으로 쓰면 루비 코드의 결과를 문자열로 변환해준다. 만약 # { } 안의 표현식이 전역 변수나 클래스 변수, 인스턴스 변수라면 중괄호를 생략해도 된다.
"Seconds/day : #{24*60*60}" # => Seconds/day: 86400
"#{'Ho! '*3}Merry Christmas!" # => Ho! Ho! ho1 Merry Christmas!
"Safe level is #SAFE" # => Safe level is 0
삽입되는 코드는 다순한 표현식뿐 아니라 한 줄 이상의 문장들이어도 무방하다.
puts "now is #{ def the(a)
'the ' + a
end
the('time')
} for all bad coders... "
실행결과
now is the time for all bad coders...
문자열과 인코딩
모든 문자열은 연관된(associated) 인코딩을 가지고 있다. 문자열의 기본인코딩은 소스 파일의 인코딩에 의해 결정된다. 명시적인 인코딩 설정이 없다면 루비 1.9에서는 US-ASCII가 되고 루비 2부터는 UTF-8이 된다.
plain_string = "dog"
puts RUBY_VERSION
puts "Encoding of #{plain_string.inspect} is #{plain_string.encoding}"
실행결과
2.0.0
Encoding of "dof" is UTF-8
파일의 인코딩을 변경하면 파일 내의 모든 문자열의 인코딩 또한 변경된다.
문자열 다루기
String 클래스는 루비 내장 클래스 중에 가장 클 것이다. 100개 이상의 표준 메서드가 정의되어 있다.
아래의 예시를 String Class 를 통해 다뤄보자
/jazz/j00123.mp3 | 3:45 | Fats Waller |Ain't Misbehavin'
/jazz/j00319.mp3 | 2:58 | Louis Armstrong | Wonderful world
한 줄을 필드별로 자르기 : String#split 메서드의 정규식 표현 /\s* | \s*/ 을 사용하면 공백을 선택적으로 포함한 세로 막대로 나뉜 토큰 배열을 만들고 String#chomp를 이용해서 줄 바꿈을 제거해야 한다.
기타 내용은 책 참조..
범위
루비에서는 시퀀스(sequence), 조건(conditiion), 간격(interval)을 구현하는데 범위를 사용한다.
범위로 시퀀스 표현하기
범위의 가장 자연스러운 사용법은 시퀀스를 표현하는 것이다. 시퀀스는 시작값, 종료값을 비롯해 차례로 값을 만들어 내는 방법으로 이뤄진다.
점 두개의 연산자는 경계를 포함하고 반면 세 개로 이뤄진 범위는 종료값 쪽의 경계를 포함하지 않는다.
1..10
'a'..'z'
0..."cat".length
범위는 to_a 메서드를 사용해 배열로 반환하거나, to_enum 메서드를 사용해 Enumerator 객체로 변환할 수 있다.
(1..10).to_a # => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
('bar'..'bat'.to_a # => ["bar", "bas", "bat"]
enum = ('bar'..'bat').to_enum
enum.next # => "bar"
enum.next # => "bas"
범위는 구성 요소를 반복할 수 있는 메서드와 내용을 다양한 방법으로 검색할수 있는 방법을 제공한다.
digist = 0..9
digits.include?(5) # => true
digits.mas # => 9
digits.reject { | i | i < 5 } # => {5, 6, 7, 8, 9}
digits.inject(:+) # => 45
루비에서는 직접만든 객체도 범위를 지원하도록 할 수 있다. 이를 위해서는 객체가 순서대로 다음 객체를 반환하는 succ 메서드를 구현해야 하고 비교 연산자 < = > 를 이용하여 비교 가능해야 한다. < = > 비교 연산자는 두 값을 비교하여 첫째 값이 둘째 값보다 작으면 -1 같으면 0 크면 +1을 반환한다.
2의 제곱수가 되는 수들을 나타내는 클래스이다. <=>와 succ가 정의되어 있으므로 클래스의 객체를 범위처럼 쓸 수 있다.
class PowerOfTwo
attr_reader :value
def initialize(value)
@value = value
end
def <=>(other)
@value <=> other.value
end
def succ
PowerOfTwo.new(@value + @value)
end
def to_s
@value.to_s
end
end
p1 = PowerOfTwo.new(4)
p2 = PowerOfTwo.new(32)
puts(p1..p2).to_a
실행결과
4
8
16
32
범위로 조건 표현하기
범위를 조건절에 사용할 수있다. 조건절에서는 일종의 토글 스위치처럼 작동한다. 스위치는 범위의 첫부분에 있는 조건이 참이 되면 켜지고 둘재 부분의 조건이 참이되면 꺼진다.
아래의 코드는 표준 입력에서 몇 부분을 출력한다. 출력되는 부분의 첫 줄은 단어 start를 포함하고 마지막 줄은 단어 end를 포함한다.
while line = gets
puts line if line =~ /start/ .. line =~ /end/
end
이 코드는 한줄을 읽을 때마다 범위에 포함되는지 여부를 판단한다.
범위로 간격 표현하기
범위의 마지막 용도는 어떤 값이 범위에 포함되는지 따지는 인터벌(interval) 테스트다. 이를 위해 case 문에서 사용하는 동등 연산자 ===를 이용한다.
(1..10) === 5 # => true
(1..15) === 15 # => false
('a'..'j') === 'c' # => true
('a'..'j') === 'z' # => false
간격 테스트는 case 문에서 자주 사용된다.
car_age = gets.to_f # 9.5가 입력되었다.
case car_age
when 0...1
#....
when 1...3
#...
when 3...10
#...
when 10...30
#...
else
#...
위의 예제의 조건에는 마지막을 포함하지 않는 범위(...)을 사용하고 있다. case 문에서는 일반적으로 ...을 사용하는 것이 좋다.
아래의 코드에서는 ..을 사용하면 9.5는 어떠한 범위에도 속하지 않게된다.
case car_age
when 0..1
#....
when 1..3
#...
when 3..10
#...
when 10..30
#...
끄읕