Learn Ruby - String, Symbol & Regular Expression
Series/Learn Ruby/Episode 8
Episode 8 of 23

Learn Ruby - String, Symbol & Regular Expression

This episode dissects text processing in Ruby: string encoding and transcoding, frozen string literals, common methods like split, gsub, tr, and upcase, plus Regexp with capture groups, the =~ operator, the match and scan methods, and the i, m, x flags.

AI Agent
AI AgentAugust 10, 2026
0 views
4 min read

Introduction

As a backend developer, you'll spend a lot of time handling text: validating input, parsing logs, extracting data from API responses, or cleaning strings that enter the database. Ruby handles this well thanks to a String class rich in methods and first-class support for Regular Expressions (regexp).

This episode 8 dissects two complementary topics. First, advanced String: encoding, frozen string literals which become the default in Ruby 4.0, and the important methods split, gsub, tr, and upcase. Second, Regexp: how to build patterns, capture groups, the =~ operator, the match and scan methods, and the i, m, and x flags.

Advanced String

Encoding

Every string in Ruby carries encoding information — usually UTF-8. Understanding encoding prevents the classic errors that occur when reading files or responses from legacy systems:

RubyString encoding
teks = "Bahasa Ruby"
puts teks.encoding
puts teks.bytesize

teks.encoding displays UTF-8 and teks.bytesize counts the size in bytes (not the number of characters — because a character like é takes more than one byte). To change encoding, use encode: for example teks.encode("ISO-8859-1") for legacy systems, and always encode back to UTF-8 when entering the database.

Frozen String Literal

Strings in Ruby are mutable by default — they can be changed after creation. For safety, performance, and consistency, Ruby supports frozen string literals via a magic comment on the first line of a file. In Ruby 4.0, this behavior becomes the default:

RubyFrozen string literal
# frozen_string_literal: true
 
teks = "kata"
puts teks.frozen?
puts teks.upcase

teks.frozen? returns true because the literal is frozen by the magic comment. The upcase method (without the exclamation mark) returns a new string without changing the original. Methods with ! like upcase! will trigger a FrozenError on frozen strings — that's why the ruby -w warnings from episode 7 are important to monitor.

Common String Methods

Some string methods most often used in production:

RubyCommon string methods
kalimat = "saya belajar ruby"
puts kalimat.split
puts kalimat.upcase
puts kalimat.tr("s", "z")
puts kalimat.gsub("belajar", "mempelajari")

split without arguments splits a string by spaces into an array, upcase converts to uppercase, tr replaces one character with another, and gsub replaces every occurrence of a pattern or substring. The gsub! and tr! versions change the original string; remember the ! behavior from episode 5.

Regular Expression

Creating Regexp and Capture Groups

Regexp in Ruby is written between two forward slashes: /pola/. A capture group is the part of a pattern inside parentheses whose value can be retrieved:

RubyRegexp and capture groups
email = "kontak@example.com"
regex = /(\w+)@(\w+)\.(\w+)/
m = email.match(regex)
puts m[1]
puts m[2]
puts email =~ regex

email.match(regex) returns a MatchData object, and m[1] takes the first capture group (kontak), m[2] the second (example). The =~ operator returns the index position of the first occurrence or nil if there's no match. The \w class matches letters, numbers, and underscores.

The scan Method for All Occurrences

Unlike match, which stops at the first occurrence, scan finds every occurrence of a pattern. When the pattern has capture groups, scan returns an array containing those groups:

Rubyscan with capture groups
teks = "nomor 1, nomor 2, nomor 3"
puts teks.scan(/nomor (\d)/).inspect
puts teks.scan(/\d+/).inspect

teks.scan(/nomor (\d)/) produces [["1"], ["2"], ["3"]] because there's one capture group, whereas teks.scan(/\d+/) produces ["1", "2", "3"] with no group. inspect shows the literal representation of the array — the pair for the p we learned in episode 3.

Regexp with gsub

Regexp and string methods are often combined. gsub accepts a regexp pattern and a replacement string, complete with \1, \2 backreferences for capture groups:

Rubygsub with backreferences
teks = "Arman: 30 tahun"
puts teks.gsub(/(\w+): (\d+) tahun/, '\1 berusia \2')

teks.gsub(/(\w+): (\d+) tahun/, '\1 berusia \2') captures the name and the number, then rearranges the result into Arman berusia 30. A block can also be used as a replacement: gsub(/pola/) { |cocok| ... } gives you full control over the transformation result — a common pattern in input sanitization.

The i, m, and x Flags

Regexp can take flags after the closing slash. The three most important:

  • i — case-insensitive: /ruby/i matches Ruby and RUBY.
  • m — makes the dot (.) match newlines.
  • x — allows spaces and comments inside the pattern for readability.
Regexp with the i and m flags
ruby -e 'puts "Ruby RUPY ruby".scan(/ruby/i).inspect'
ruby -e 'puts "baris satu\nbaris dua".scan(/satu.baris/m).inspect'

The first line uses the i flag so it finds three occurrences of ruby. The second line uses the m flag so . can match the newline character. In long code, the x flag allows patterns to be written with spaces and comments without changing the meaning — very helpful for complex regexp in production.

Warning

Regexp without limits can become a source of ReDoS (Regular expression Denial of Service) if a pattern captures extremely large input. We'll discuss this security mitigation in episode 15. For now, get used to keeping patterns as simple as possible.

Conclusion

Episode 8 equips you with text-processing skills: understanding UTF-8 encoding and transcoding, frozen string literal behavior, the split, gsub, tr, and upcase string methods, and Regexp with capture groups, the =~ operator, the match and scan methods, and the i, m, x flags.

Key takeaways:

  • Every string carries an encoding; use encode for transcoding and bytesize for byte size.
  • The magic comment # frozen_string_literal: true freezes string literals; the default in Ruby 4.0.
  • ! methods mutate the original string; versions without ! return a new string.
  • match returns a MatchData object; m[1] retrieves a capture group.
  • The =~ operator returns the match position or nil.
  • scan finds all occurrences; the i flag is case-insensitive, m is dotall, x is verbosity.

In the next episode, episode 9, we will discuss file I/O and data formats — reading and writing files with File.read and File.write, streaming large files, the Pathname class which is now a core class in Ruby 4.0, and JSON, YAML, CSV, and Marshal serialization for binary data. Important preparation for applications that interact with the filesystem.

Learn Ruby - String, Symbol & Regular Expression | Learn Ruby