Scala - String Operations with Examples
• Scala strings are immutable Java String objects with enhanced functionality through implicit conversions to StringOps, providing functional programming methods like map, filter, and fold
Key Insights
• Scala strings are immutable Java String objects with enhanced functionality through implicit conversions to StringOps, providing functional programming methods like map, filter, and fold • String interpolation in Scala offers three built-in interpolators (s, f, raw) and supports custom interpolators for domain-specific formatting needs • Pattern matching with regular expressions and extractors enables powerful string parsing and transformation capabilities beyond traditional imperative approaches
String Basics and Immutability
Scala strings are instances of java.lang.String, making them immutable by design. Every string operation returns a new string rather than modifying the original.
val original = "Hello"
val modified = original.concat(" World")
println(original) // Hello
println(modified) // Hello World
// Common operations
val text = "Scala Programming"
println(text.length) // 17
println(text.toLowerCase) // scala programming
println(text.substring(0, 5)) // Scala
println(text.replace("a", "A")) // ScAlA ProgrAmming
Scala enriches Java strings through implicit conversion to StringOps, providing functional methods:
val str = "functional"
// Using functional methods
str.filter(_.isUpper) // ""
str.map(_.toUpper) // "FUNCTIONAL"
str.exists(_.isDigit) // false
str.forall(_.isLetter) // true
str.take(4) // "func"
str.drop(4) // "tional"
String Interpolation
Scala provides three built-in interpolators that prefix string literals.
s-interpolator for variable substitution:
val name = "Alice"
val age = 30
val greeting = s"Hello, $name! You are $age years old."
println(greeting) // Hello, Alice! You are 30 years old.
// Expression evaluation
val result = s"Next year you'll be ${age + 1}."
println(result) // Next year you'll be 31.
// Accessing object properties
case class Person(firstName: String, lastName: String)
val person = Person("John", "Doe")
println(s"Full name: ${person.firstName} ${person.lastName}")
f-interpolator for formatted output:
val price = 19.99
val quantity = 3
val total = price * quantity
println(f"Price: $$${price}%.2f") // Price: $19.99
println(f"Quantity: $quantity%d") // Quantity: 3
println(f"Total: $$${total}%.2f") // Total: $59.97
// Padding and alignment
val items = List(("Apple", 1.50), ("Banana", 0.75), ("Orange", 2.25))
items.foreach { case (name, price) =>
println(f"$name%-10s $$${price}%6.2f")
}
// Apple $ 1.50
// Banana $ 0.75
// Orange $ 2.25
raw-interpolator to avoid escape sequences:
println(s"Line1\nLine2") // Two lines
println(raw"Line1\nLine2") // Line1\nLine2 (literal)
val path = raw"C:\Users\Documents\file.txt"
println(path) // C:\Users\Documents\file.txt
Custom String Interpolators
Create domain-specific interpolators for specialized formatting:
implicit class JsonInterpolator(val sc: StringContext) extends AnyVal {
def json(args: Any*): String = {
val strings = sc.parts.iterator
val expressions = args.iterator
val buf = new StringBuilder(strings.next())
while(strings.hasNext) {
val arg = expressions.next()
val formatted = arg match {
case s: String => s""""$s""""
case n: Number => n.toString
case b: Boolean => b.toString
case _ => s""""$arg""""
}
buf.append(formatted)
buf.append(strings.next())
}
buf.toString
}
}
val name = "Bob"
val active = true
val score = 95
val jsonStr = json"""{"name": $name, "active": $active, "score": $score}"""
println(jsonStr) // {"name": "Bob", "active": true, "score": 95}
Regular Expressions and Pattern Matching
Scala’s Regex class provides powerful pattern matching capabilities:
import scala.util.matching.Regex
val pattern: Regex = "[0-9]+".r
val text = "Order 123 shipped, invoice 456 pending"
// Find first match
pattern.findFirstIn(text) match {
case Some(num) => println(s"First number: $num") // First number: 123
case None => println("No match")
}
// Find all matches
val numbers = pattern.findAllIn(text).toList
println(numbers) // List(123, 456)
// Replace matches
val masked = pattern.replaceAllIn(text, "XXX")
println(masked) // Order XXX shipped, invoice XXX pending
Extracting groups:
val emailPattern = """(\w+)@(\w+\.\w+)""".r
"user@example.com" match {
case emailPattern(user, domain) =>
println(s"User: $user, Domain: $domain") // User: user, Domain: example.com
case _ => println("Invalid email")
}
// Multiple extractions
val logEntry = "2024-01-15 ERROR Database connection failed"
val logPattern = """(\d{4}-\d{2}-\d{2})\s+(\w+)\s+(.+)""".r
logEntry match {
case logPattern(date, level, message) =>
println(s"Date: $date\nLevel: $level\nMessage: $message")
}
String Splitting and Joining
Efficient string tokenization and concatenation:
val csv = "apple,banana,cherry,date"
// Split operations
val fruits = csv.split(",")
println(fruits.mkString(" | ")) // apple | banana | cherry | date
// Split with limit
val limited = csv.split(",", 3)
println(limited.toList) // List(apple, banana, cherry,date)
// Split on whitespace
val sentence = "The quick brown fox"
val words = sentence.split("\\s+")
println(words.toList) // List(The, quick, brown, fox)
Joining collections:
val items = List("Scala", "Java", "Kotlin", "Groovy")
println(items.mkString(", ")) // Scala, Java, Kotlin, Groovy
println(items.mkString("[", ", ", "]")) // [Scala, Java, Kotlin, Groovy]
// Using StringBuilder for efficiency
val builder = new StringBuilder
items.foreach(item => builder.append(item).append("; "))
println(builder.toString) // Scala; Java; Kotlin; Groovy;
Advanced String Operations
Multi-line strings and stripMargin:
val query = """SELECT id, name, email
|FROM users
|WHERE active = true
|ORDER BY name""".stripMargin
println(query)
// Custom margin character
val json = """{
# "name": "Product",
# "price": 29.99,
# "available": true
#}""".stripMargin('#')
String comparison and ordering:
val str1 = "apple"
val str2 = "banana"
println(str1 == str2) // false
println(str1.equalsIgnoreCase("APPLE")) // true
println(str1.compareTo(str2)) // negative (apple < banana)
// Custom ordering
case class Product(name: String, price: Double)
implicit val productOrdering: Ordering[Product] =
Ordering.by(_.name)
val products = List(
Product("Laptop", 999.99),
Product("Mouse", 29.99),
Product("Keyboard", 79.99)
)
println(products.sorted.map(_.name)) // List(Keyboard, Laptop, Mouse)
Checking string properties:
val input = "Scala2024"
println(input.forall(_.isLetterOrDigit)) // true
println(input.exists(_.isDigit)) // true
println(input.count(_.isDigit)) // 4
println(input.startsWith("Scala")) // true
println(input.endsWith("2024")) // true
println(input.contains("la")) // true
// Partition based on predicate
val (letters, digits) = input.partition(_.isLetter)
println(s"Letters: $letters, Digits: $digits") // Letters: Scala, Digits: 2024
String operations in Scala combine Java’s robust string handling with functional programming paradigms. The implicit conversion to StringOps enables method chaining and collection-like operations, while string interpolation and pattern matching provide expressive syntax for common tasks. Understanding these features allows you to write concise, readable code for text processing and manipulation.