String 클래스

String 클래스

String은 Ruby에서 텍스트를 다루는 가장 기본적인 클래스예요. 문자, 단어, 문장, 문서까지 — 문자열 하나로 표현할 수 있는 건 모두 String 객체라고 보면 돼요.

출처: Ruby 4.0 API

본문

String이 담고 있는 콘텐츠는 따옴표('...' 또는 "...")나 퍼센트 리터럴(%q{...}, %Q{...} 등)로 만들 수 있어요. 또 필요에 따라 Encoding을 지정해서 인코딩(예: UTF-8)을 관리하죠.

이 문서는 String의 "무엇이 여기 있나"부터 시작해서 메서드를 알파벳 순으로 설명해요. 각 개념 섹션에 대한 자세한 설명은 아래 메서드별 문서에서 다뤄요.

무엇이 여기 있나 (What's Here)

String은 아래 카테고리로 정리할 수 있는 메서드들을 제공해요.

문자열 만들기 (Creating a New String)

  • 문자열 분해: String#bytes, String#chars, String#codepoints, String#grapheme_clusters, String#lines
  • 부분 문자열: String#[], String#byteslice, String#chr, String#slice
  • 새 문자열 만들기: String#center, String#concat, String#<<, String#dump, String#*, String#+, String#+@, String#-@

동결 (Frozen Strings)

  • String#-@self가 이미 frozen이면 self를, 아니면 임시 캐시에 있는 경우 그 frozen 문자열을 반환하거나 duplicate한 frozen 문자열을 만들어요.
  • String#+@는 un-frozen한 문자열(복사본)을 반환해요.

조회 (Querying)

  • 바이트/문자: String#bytesize, String#length, String#size, String#sum
  • 부분 문자열 판별: String#include?, String#index, String#rindex
  • 접두사/접미사: String#start_with?, String#end_with?
  • 인코딩: String#ascii_only?, String#encoding, String#valid_encoding?, String#unicode_normalized?
  • 기타: String#match?, String#casecmp, String#casecmp?, String#empty?, String#eql?, String#hash, String#match

비교 (Comparing)

  • String#==, String#<=>, String#casecmp, String#casecmp?, String#eql?, String#hash

수정 (Modifying)

  • 대체: String#sub, String#sub!, String#gsub, String#gsub!, String#tr, String#tr!, String#tr_s, String#tr_s!
  • 삽입/삭제: String#insert, String#delete, String#delete!, String#clear
  • 제거: String#bytesplice, String#squeeze, String#squeeze!, String#strip, String#strip!, String#lstrip, String#lstrip!, String#rstrip, String#rstrip!
  • 치환: String#replace, String#reverse, String#reverse!
  • 케이스: String#upcase, String#upcase!, String#downcase, String#downcase!, String#capitalize, String#capitalize!, String#swapcase, String#swapcase!
  • 셀프 수정: String#<<, String#concat, String#prepend, String#setbyte
  • 기타: String#succ!, String#next!

변환 (Converting)

  • 새 문자열로: String#to_s, String#%, String#*, String#+, String#+@, String#-@, String#dump
  • 비문자열로: String#to_i, String#to_f, String#to_r, String#to_c, String#to_sym
  • 기타: String#encode, String#scrub

반복 (Iterating)

  • String#each_byte, String#each_char, String#each_codepoint, String#each_grapheme_cluster, String#each_line, String#upto

메서드

%(format, *objects) → string

self를 최대 하나의 % 지정자(%s, %d 등)로 해석해서 포매팅된 문자열을 반환해요. %d, %f, %s 등 printf 스타일 형식 지정자를 그대로 사용할 수 있어요:

'%5d' % 123       # => "  123"
'%.2f' % 3.14159  # => "3.14"
'%s %s' % ['a', 'b'] # => "a b"

*times → new_string

selftimes번 이어붙인 새 문자열을 반환해요:

'Hello! ' * 3 # => "Hello! Hello! Hello! "

times는 0 이상의 정수여야 해요. times가 0이면 빈 문자열을, 음수면 ArgumentError를 던져요.

times에 문자열을 전달하려 하면 TypeError가 발생해요. 이는 문자열 곱셈에 대한 명확한 의미 정의가 없기 때문이에요.

+other_string → new_string

selfother_string을 이어붙인 새 문자열을 반환해요:

'Hello ' + 'World!' # => "Hello World!"

+@ → new_string

self가 frozen이면 단조된(duplicate된), un-frozen 문자열을 반환하고, 아니면 self를 그대로 반환해요.

-@ → new_string

self가 frozen이면 self를 반환하고, 아니면 (임시 캐시에 있는 경우) 그 frozen 문자열 또는 duplicate된 frozen 문자열을 반환해요.

<<object → self

object가 Integer면 이를 코드 포인트(문자)로 변환해서 self 끝에 추가하고, 그 외의 경우엔 문자열로 변환해서 이어붙여요. self를 반환하므로 체이닝이 가능하죠:

s = 'foo'
s << 'bar' # => "foobar"
s << 33    # => "foobar!"

→ new_string or nil

부분 문자열 접근의 왕이에요. 정수 인덱스, 정수 범위(방울), 시작+길이, 부분 문자열, 정규표현식(캡처 포함)까지 다양한 방식으로 문자열의 일부를 꺼냅니다.

[]=(index, ...) → object

self의 부분을 대체해요. []의 모든 형태(인덱스, 범위, 부분 문자열, 정규표현식)와 쌍을 이뤄요.

ascii_only? → true or false

self가 ASCII 문자열이면 true를, 아니면 false를 반환해요:

'abc'.ascii_only?        # => true
'abc\u{6666}'.ascii_only? # => false

b → string

self를 복제해서 ASCII-8BIT 인코딩으로 만든 새 문자열을 반환해요.

bytes → array_of_integers

self의 각 바이트를 정수 배열로 반환해요:

'hello'.bytes # => [104, 101, 108, 108, 111]

byteslice(index, ...) → new_string or nil

바이트 단위로 부분 문자열을 반환해요. []와 비슷하지만 인덱스를 바이트 기준으로 다뤄요.

bytesize → integer

문자열의 바이트 수를 반환해요. String#length가 문자(코드 포인트) 수를 센다면, bytesize는 원시 바이트 수를 세죠:

'foo'.bytesize        # => 3
'fooé'.bytesize       # => 5

bytesplice(*args) → self

self의 일부를 대체하되, 인덱스를 바이트 단위로 다뤄요. 정수 위치 + 다른 문자열, 또는 범위, 또는 부분 문자열 + 길이 형태로 호출할 수 있어요.

capitalize(mapping = :ascii) → new_string

첫 글자는 대문자로, 나머지는 소문자로 만든 새 문자열을 반환해요:

'hello'.capitalize        # => "Hello"
'HELLO'.capitalize        # => "Hello"
'123abc'.capitalize       # => "123abc"

케이스 매핑은 :ascii, :fold, :turkic 옵션의 영향을 받아요.

capitalize!(mapping) → self or nil

capitalize와 같되 self를 직접 수정해요. 변경이 있으면 self, 없으면 nil을 반환해요.

casecmp(other_string) → -1, 0, 1, or nil

대소문자를 무시하고 비교해요. 두 문자열이 같은 문자라도 케이스만 다르면 같다고 봐요:

'abc'.casecmp('ABC')  # => 0
'abcdef'.casecmp('ABC') # => 1   # 'd' > 'C' 비교

둘 중 하나라도 ASCII가 아니라면 케이스-폴딩 없이 비교돼요.

casecmp?(other_string) → true, false, or nil

casecmp와 같지만 불리언을 반환해요:

'abc'.casecmp?('ABC') # => true
'abc'.casecmp?('xyz') # => false

center(width, pad_string = ' ') → new_string

왼쪽과 오른쪽에 pad_string을 넣어 selfwidth만큼 가운데 정렬한 새 문자열을 반환해요:

'abc'.center(7)        # => "  abc  "
'abc'.center(7, '-')   # => "--abc--"
'abc'.center(2)        # => "abc"   # width가 더 짧으면 그대로

chars → array_of_strings

self를 문자(코드 포인트) 배열로 반환해요:

'hello'.chars # => ["h", "e", "l", "l", "o"]

chomp(line_sep = $/) → new_string

문자열 끝에서 레코드 구분자(기본 $/, "\n")를 제거한 복사본을 반환해요:

'hello'.chomp                # => "hello"
'hello\n'.chomp              # => "hello"
'hello\r\n'.chomp            # => "hello"
'hello\n\n'.chomp            # => "hello\n"
'hello'.chomp('llo')         # => "he"

chr → string

self의 첫 문자를 담은 새 문자열을 반환해요:

'glark'.chr # => "g"

clear → self

self를 빈 문자열로 만들어요:

s = 'foo'
s.clear # => ""

codepoints → array_of_integers

self의 각 문자의 코드 포인트를 정수 배열로 반환해요:

'hello'.codepoints # => [104, 101, 108, 108, 111]

concat(*objects) → self

objectself 끝에 이어붙여요. <<와 같은 기능이에요.

count(*selectors) → integer

selectors(문자 선택자)에 해당하는 문자들의 총 개수를 반환해요:

'hello'.count('l')          # => 2
'hello'.count('lo')         # => 3
'hello'.count('a-e')        # => 1   # 'e'만 해당
'hello'.count('^l')         # => 3   # 부정
'hello'.count('h', 'l')     # => 3   # 다중 셀렉터는 합집합

crypt(*args) → string (⚠️ 2.6에서 deprecated)

delete(*selectors) → new_string

셀렉터에 해당하는 문자를 제거한 복사본을 반환해요:

'hello'.delete('l')     # => "heo"
'hello'.delete('lo')    # => "he"
'hello'.delete('a-e')   # => "hllo"
'hello'.delete('^l')    # => "ll"
'hello'.delete('h', 'l') # => "eo"

delete!(*selectors) → self or nil

delete와 같되 self를 직접 수정해요.

delete_prefix(prefix) → new_string

selfprefix로 시작하면 그 부분을 제거한 복사본을 반환해요:

'hello'.delete_prefix('hel') # => "lo"
'hello'.delete_prefix('lo')  # => "hello"   # 안 맞으면 그대로

delete_suffix(suffix) → new_string

selfsuffix로 끝나면 그 부분을 제거한 복사본을 반환해요:

'hello'.delete_suffix('llo') # => "he"

downcase(mapping = :ascii) → new_string

소문자로 만든 복사본을 반환해요:

'hello'.downcase # => "hello"
'HELLO'.downcase # => "hello"

dump → new_string

self에서 따옴표를 벗기고 비인쇄 문자를 이스케이프한, 복사 가능한 리터럴 형태의 문자열을 반환해요. String#undump의 역연산이에요:

'hello'.dump # => "\"hello\""

each_byte {|byte| ... } → self

각 바이트를 정수로 블록에 넘겨요. 블록 없이 호출하면 Enumerator를 반환해요.

each_char {|char| ... } → self

각 문자를 블록에 넘겨요:

'hello'.each_char {|c| print c, ' ' } # => h e l l o

each_codepoint {|int| ... } → self

각 코드 포인트를 정수로 블록에 넘겨요.

each_grapheme_cluster {|clstr| ... } → self

각 그래핌 클러스터(사용자가 문자로 인식하는 단위, 예: 조합 자모)를 블록에 넘겨요.

each_line(line_sep = $/, chomp: false) {|substring| ... } → self

각 줄을 블록에 넘겨요. chomp: true를 주면 각 줄의 끝 줄바꿈을 제거해요:

"foo\nbar\n".each_line {|line| p line }
# "foo\n"
# "bar\n"

empty? → true or false

self가 비어 있으면 true:

'glark'.empty? # => false
''.empty?      # => true

encode(*encodings, **options) → string

self를 지정한 인코딩으로 변환한 새 문자열을 반환해요.

encode!(*encodings, **options) → self

encode와 같되 self를 직접 변환해요.

encoding → encoding

selfEncoding 객체를 반환해요.

end_with?(*patterns) → true or false

self가 주어진 패턴 중 하나로 끝나면 true:

'hello'.end_with?('llo')   # => true
'hello'.end_with?('O')     # => false (대소문자 구분)

eql?(object) → true or false

문자열과 인코딩이 모두 같으면 true. 객체 비교에 사용돼요 (==보다 엄격).

force_encoding(encoding) → self

인코딩을 바꿔도 바이트는 그대로 유지한 채 메타데이터만 바꿔요:

s = 'glark'
s.force_encoding(Encoding::ASCII_8BIT) # => "glark"

freeze → self

문자열을 동결(freeze)해요.

getbyte(index) → integer or nil

gsub(pattern, replacement) → new_string

pattern과 일치하는 모든 부분을 replacement로 바꾼 복사본을 반환해요. replacement로 문자열 또는 해시가 올 수 있고, 블록을 주면 각 일치부에 대해 블록을 호출해요:

'Hello'.gsub(/[aeiou]/, '*') # => "H*ll*"

gsub!(pattern, replacement) → self or nil

gsub와 같되 self를 직접 수정해요.

hash → integer

문자열의 해시 값을 반환해요.

hex → integer

수정자 접두어(0x 등)까지 해석해서 십육진수로 해석해요:

'0x0a'.hex   # => 10
'-1234'.hex  # => -4660

include?(other_string) → true or false

other_string이 부분 문자열로 포함되어 있으면 true:

'hello'.include?('lo')  # => true
'hello'.include?('ol')  # => false

index(substring, offset = 0) → integer or nil

initialize_copy(other_string) → self

insert(index, other_string) → self

intern → symbol (== to_sym)

length → integer (== size, 문자 수)

lines(separator = $/, chomp: false) → array_of_strings

lstrip → new_string

match?(pattern, offset = 0) → true or false

next → new_string (== succ)

oct → integer

ord → integer

partition(sep) → [head, sep, tail]

prepend(*other_strings) → self

replace(other_string) → self

reverse → new_string

rindex(*args) → integer or nil

rpartition(sep) → [head, sep, tail]

rstrip → new_string

scan(pattern) → array or self

scrub(*args) → new_string

setbyte(index, integer) → integer

shellescape → string

shellsplit → array

slice(...) → new_string or nil (== [])

split(field_sep, limit = 0) → array_of_substrings

squeeze(*selectors) → new_string

start_with?(*patterns) → true or false

strip(*selectors) → new_string

sub(pattern, replacement) → new_string

succ → new_string

sum(n = 16) → integer

swapcase(mapping = :ascii) → new_string

to_c → complex

to_f → float

to_i(base = 10) → integer

to_json_raw(*args)

to_json_raw_object()

to_r → rational

to_s → self or new_string

tr(selector, replacements) → new_string

tr_s(selector, replacements) → new_string

undump → new_string

unicode_normalize(form = :nfc) → string

unicode_normalize!(form = :nfc) → self

unicode_normalized?(form = :nfc) → true or false

unpack(template, offset: 0) {|o| ... } → object

unpack1(template, offset: 0) → object

upcase(mapping = :ascii) → new_string

upto(other_string, exclusive = false) {|string| ... } → self

valid_encoding? → true or false

주요 메서드 자세히

String은 위 목록처럼 매우 많은 메서드를 갖고 있어요. 특히 실무에서 자주 쓰는 것들을 골라 조금 더 자세히 볼게요.

split

구분자 기준으로 문자열을 잘라 배열로 돌려줘요. 구분자는 문자열, 정규표현식, 또는 기본 $/일 수 있어요:

'abracadabra'.split('a') # => ["", "br", "c", "d", "br"]
'foo bar baz'.split(' ') # => ["foo", "bar", "baz"]
'1, 2, 3'.split(', ')    # => ["1", "2", "3"]
'1 + 1 == 2'.split(/\W+/) # => ["1", "1", "2"]

limit 인자로 반환 배열 크기를 제한하거나, 빈 문자열 포함 여부를 조절할 수 있어요:

'abracadabra'.split('', 3)   # => ["a", "b", "racadabra"]
'abracadabra'.split('a', -1) # => ["", "br", "c", "d", "br", ""]

sub / gsub

pattern과 일치하는 첫 부분만(sub) 또는 전부(gsub)를 replacement로 치환해요. replacement가 문자열이면 그대로, 해시면 일치한 키를 값으로 치환하고, 블록이면 블록 반환 값으로 치환돼요:

s = 'abracadabra'
s.sub('bra', 'xyzzy')  # => "axyzzycadabra"
s.gsub('bra', 'xyzzy') # => "axyzzycadaxyzzy"
s.gsub(/[aeiou]/, '*') # => "*br*c*d*br*"

문자 선택자 (Character Selectors)

count, delete, squeeze, strip, tr 등은 "문자 선택자"를 받아요. 선택자는:

  • 단일 문자: 'o'
  • 여러 문자: 'aeiou'
  • 범위: 'a-z'
  • 부정: '^aeiou'
  • 이스케이프: '\\^', '\\-', '\\\\'
'Mississippi'.squeeze('s')   # => "Misisippi"
'Mississippi'.squeeze('sp')  # => "Misisipi"
'Mississippi'.squeeze('a-p') # => "Mississipi"

to_i / to_f / to_r / to_c

문자열 앞부분을 숫자로 해석하는 변환 메서드들이에요:

'123456'.to_i        # => 123456
'3.14159'.to_f       # => 3.14159
'123'.to_r           # => (123/1)
'2+3i'.to_c.rect     # => [2, 3]

String은 Ruby에서 가장 많이 쓰이는 클래스라서, 이렇게 카테고리별로 정리해 두면 필요한 메서드를 빠르게 찾을 수 있어요.