Skip to content

Scala Strings

Strings are one of the most commonly used data types in programming. Strings in Scala are based on Java's String class, but provide more convenient operation methods and syntactic sugar.

String Basics

String Creation

scala
object StringCreation {
  def main(args: Array[String]): Unit = {
    // Basic string creation
    val str1 = "Hello, World!"
    val str2 = new String("Hello, World!")
    
    // Empty strings
    val emptyStr1 = ""
    val emptyStr2 = String.empty
    
    // Create from character array
    val charArray = Array('H', 'e', 'l', 'l', 'o')
    val str3 = new String(charArray)
    
    println(str1)
    println(str2)
    println(s"Empty string length: ${emptyStr1.length}")
    println(str3)
    
    // String comparison
    println(s"str1 == str2: ${str1 == str2}")  // true (content comparison)
    println(s"str1 eq str2: ${str1 eq str2}")  // false (reference comparison)
  }
}

String Literals

scala
object StringLiterals {
  def main(args: Array[String]): Unit = {
    // Regular strings
    val normal = "This is a regular string"
    
    // Strings with escape characters
    val escaped = "First line\nSecond line\tTabbed text\\Backslash\\""
    
    // Raw strings (triple quotes)
    val raw = """This is a raw string
                |Can contain newlines
                |and "quotes" without escaping
                |Backslash \ also not needs escaping""".stripMargin
    
    // Multi-line strings
    val multiline = 
      """SELECT name, age
        |FROM users
        |WHERE age > 18
        |ORDER BY name""".stripMargin
    
    println(normal)
    println(escaped)
    println(raw)
    println(multiline)
  }
}

String Interpolation

s Interpolator

scala
object SInterpolation {
  def main(args: Array[String]): Unit = {
    val name = "Alice"
    val age = 25
    val height = 1.68
    
    // s interpolator - basic usage
    val greeting = s"Hello, my name is $name"
    val info = s"I am $age years old and ${height}m tall"
    
    // Expression interpolation
    val calculation = s"Next year I will be ${age + 1} years old"
    val formatted = s"Height in cm: ${height * 100}"
    
    println(greeting)
    println(info)
    println(calculation)
    println(formatted)
    
    // Complex expressions
    val numbers = List(1, 2, 3, 4, 5)
    val summary = s"Numbers: ${numbers.mkString(", ")}, Sum: ${numbers.sum}"
    println(summary)
  }
}

f Interpolator (Formatting)

scala
object FInterpolation {
  def main(args: Array[String]): Unit = {
    val name = "Bob"
    val score = 85.6789
    val percentage = 0.856
    
    // f interpolator - formatted output
    val formatted1 = f"$name scored $score%.2f points"
    val formatted2 = f"Percentage: $percentage%.1%%"  // %% represents % character
    
    // Number formatting
    val pi = 3.14159265359
    val formatted3 = f"Pi to 3 decimal places: $pi%.3f"
    val formatted4 = f"Pi in scientific notation: $pi%.2e"
    
    // String formatting
    val formatted5 = f"Name: $name%10s"  // Right aligned, width 10
    val formatted6 = f"Name: $name%-10s|"  // Left aligned, width 10
    
    println(formatted1)
    println(formatted2)
    println(formatted3)
    println(formatted4)
    println(formatted5)
    println(formatted6)
  }
}

raw Interpolator

scala
object RawInterpolation {
  def main(args: Array[String]): Unit = {
    val path = "C:\\Users\\Alice\\Documents"
    
    // raw interpolator - does not process escape characters
    val rawString = raw"Path: $path\nThis \t will \\ not \\ be \\ escaped"
    val normalString = s"Path: $path\nThis \t will \\ be \\ escaped"
    
    println("Raw interpolation:")
    println(rawString)
    println("\nNormal interpolation:")
    println(normalString)
    
    // Useful in regular expressions
    val regex = raw"\d{3}-\d{2}-\d{4}"  // No need to double escape
    println(s"Regex pattern: $regex")
  }
}

String Operations

Basic Operations

scala
object BasicStringOperations {
  def main(args: Array[String]): Unit = {
    val str = "Hello, Scala World!"
    
    // Length and index
    println(s"Length: ${str.length}")
    println(s"First character: ${str(0)}")
    println(s"Last character: ${str(str.length - 1)}")
    
    // Substrings
    println(s"Substring(0, 5): ${str.substring(0, 5)}")
    println(s"Substring(7): ${str.substring(7)}")
    
    // Find operations
    println(s"Index of 'Scala': ${str.indexOf("Scala")}")
    println(s"Last index of 'l': ${str.lastIndexOf('l')}")
    println(s"Contains 'World': ${str.contains("World")}")
    
    // Case conversions
    println(s"Uppercase: ${str.toUpperCase}")
    println(s"Lowercase: ${str.toLowerCase}")
    
    // Trim whitespace
    val paddedStr = "  Hello, World!  "
    println(s"Trimmed: '${paddedStr.trim}'")
    
    // Replacement
    println(s"Replace 'World' with 'Scala': ${str.replace("World", "Scala")}")
    println(s"Replace first 'l' with 'L': ${str.replaceFirst("l", "L")}")
  }
}

String Splitting and Joining

scala
object StringSplitJoin {
  def main(args: Array[String]): Unit = {
    val csv = "apple,banana,orange,grape"
    val sentence = "The quick brown fox jumps over lazy dog"
    
    // Split strings
    val fruits = csv.split(",")
    val words = sentence.split(" ")
    
    println("Fruits:")
    fruits.foreach(println)
    
    println("\nWords:")
    words.foreach(println)
    
    // Join strings
    val joined1 = fruits.mkString(" | ")
    val joined2 = words.mkString("[", ", ", "]")
    
    println(s"\nJoined fruits: $joined1")
    println(s"Joined words: $joined2")
    
    // Use separator
    val numbers = Array(1, 2, 3, 4, 5)
    val numberString = numbers.mkString(", ")
    println(s"Numbers: $numberString")
    
    // String builder
    val sb = new StringBuilder()
    sb.append("Hello")
    sb.append(", ")
    sb.append("World")
    sb.append("!")
    
    println(s"StringBuilder result: ${sb.toString}")
  }
}

String Matching and Regular Expressions

scala
import scala.util.matching.Regex

object StringMatching {
  def main(args: Array[String]): Unit = {
    val text = "My phone number is 123-456-7890 and email is user@example.com"
    
    // Regular expressions
    val phonePattern: Regex = """\d{3}-\d{3}-\d{4}""".r
    val emailPattern = """[\w._%+-]+@[\w.-]+\.[A-Za-z]{2,}""".r
    val datePattern = """\d{4}-\d{2}-\d{2}""".r
    
    // Find matches
    val phoneMatch = phonePattern.findFirstIn(text)
    val emailMatch = emailPattern.findFirstIn(text)
    
    println(s"Phone: ${phoneMatch.getOrElse("Not found")}")
    println(s"Email: ${emailMatch.getOrElse("Not found")}")
    
    // Find all matches
    val numbers = """\d+""".r
    val allNumbers = numbers.findAllIn("There are 123 apples and 456 oranges").toList
    println(s"All numbers: $allNumbers")
    
    // Replace matches
    val censored = phonePattern.replaceAllIn(text, "XXX-XXX-XXXX")
    println(s"Censored: $censored")
    
    // Pattern matching
    val input = "user@domain.com"
    input match {
      case emailPattern() => println("Valid email format")
      case _ => println("Invalid email format")
    }
    
    // Extract groups
    val namePattern = """(\w+)\s+(\w+)""".r
    val fullName = "John Doe"
    fullName match {
      case namePattern(first, last) => 
        println(s"First name: $first, Last name: $last")
      case _ => 
        println("Name pattern not matched")
    }
  }
}

String Advanced Operations

String Conversion

scala
object StringConversion {
  def main(args: Array[String]): Unit = {
    // String to numbers
    val numberStr = "123"
    val floatStr = "3.14"
    val boolStr = "true"
    
    val intValue = numberStr.toInt
    val floatValue = floatStr.toFloat
    val boolValue = boolStr.toBoolean
    
    println(s"String to Int: $intValue")
    println(s"String to Float: $floatValue")
    println(s"String to Boolean: $boolValue")
    
    // Safe conversion
    def safeToInt(str: String): Option[Int] = {
      try {
        Some(str.toInt)
      } catch {
        case _: NumberFormatException => None
      }
    }
    
    println(s"Safe conversion '123': ${safeToInt("123")}")
    println(s"Safe conversion 'abc': ${safeToInt("abc")}")
    
    // String to collections
    val str = "Hello"
    val charList = str.toList
    val charArray = str.toCharArray
    
    println(s"String to List: $charList")
    println(s"String to Array: ${charArray.mkString("[", ", ", "]")}")
    
    // Numbers to strings
    val num = 42
    val numStr1 = num.toString
    val numStr2 = String.valueOf(num)
    
    println(s"Number to String: $numStr1")
    println(s"Using valueOf: $numStr2")
  }
}

String Formatting

scala
object StringFormatting {
  def main(args: Array[String]): Unit = {
    val name = "Alice"
    val age = 30
    val salary = 50000.0
    
    // Use format method
    val formatted1 = "Name: %s, Age: %d, Salary: %.2f".format(name, age, salary)
    println(formatted1)
    
    // Positional arguments
    val formatted2 = "Hello %1$s, you are %2$d years old. Nice to meet you, %1$s!".format(name, age)
    println(formatted2)
    
    // Number formatting
    val pi = 3.14159265359
    println(f"Pi: $pi%8.3f")  // Width 8, 3 decimal places
    println(f"Pi: $pi%08.3f") // Pad with zeros
    println(f"Pi: $pi%-8.3f") // Left align
    
    // Percentage formatting
    val percentage = 0.75
    println(f"Success rate: $percentage%.1%%")
    
    // Scientific notation
    val bigNumber = 1234567.89
    println(f"Big number: $bigNumber%.2e")
    
    // Hexadecimal
    val number = 255
    println(f"Hex: $number%x")
    println(f"Hex (uppercase): $number%X")
  }
}

String Performance Optimization

scala
object StringPerformance {
  def main(args: Array[String]): Unit = {
    // String concatenation performance comparison
    def concatenateWithPlus(n: Int): String = {
      var result = ""
      for (i <- 1 to n) {
        result += s"Item $i "
      }
      result
    }
    
    def concatenateWithBuilder(n: Int): String = {
      val sb = new StringBuilder()
      for (i <- 1 to n) {
        sb.append(s"Item $i ")
      }
      sb.toString
    }
    
    def concatenateWithMkString(n: Int): String = {
      (1 to n).map(i => s"Item $i").mkString(" ")
    }
    
    // Performance test
    val n = 1000
    
    val start1 = System.currentTimeMillis()
    val result1 = concatenateWithPlus(n)
    val time1 = System.currentTimeMillis() - start1
    
    val start2 = System.currentTimeMillis()
    val result2 = concatenateWithBuilder(n)
    val time2 = System.currentTimeMillis() - start2
    
    val start3 = System.currentTimeMillis()
    val result3 = concatenateWithMkString(n)
    val time3 = System.currentTimeMillis() - start3
    
    println(s"String concatenation with +: ${time1}ms")
    println(s"StringBuilder: ${time2}ms")
    println(s"mkString: ${time3}ms")
    
    // String pool
    val str1 = "Hello"
    val str2 = "Hello"
    val str3 = new String("Hello")
    
    println(s"str1 eq str2: ${str1 eq str2}")  // true (string pool)
    println(s"str1 eq str3: ${str1 eq str3}")  // false (new object)
    println(s"str1 == str3: ${str1 == str3}")  // true (same content)
  }
}

Practical Application Examples

Text Processing Tool

scala
object TextProcessor {
  def wordCount(text: String): Map[String, Int] = {
    text.toLowerCase
      .replaceAll("[^a-zA-Z\\s]", "")  // Remove punctuation
      .split("\\s+")                   // Split by whitespace
      .filter(_.nonEmpty)              // Filter empty strings
      .groupBy(identity)               // Group by word
      .view.mapValues(_.length).toMap  // Count occurrences of each word
  }
  
  def reverseWords(text: String): String = {
    text.split(" ").map(_.reverse).mkString(" ")
  }
  
  def isPalindrome(text: String): Boolean = {
    val cleaned = text.toLowerCase.replaceAll("[^a-zA-Z0-9]", "")
    cleaned == cleaned.reverse
  }
  
  def capitalizeWords(text: String): String = {
    text.split(" ").map(word => 
      if (word.nonEmpty) word.head.toUpper + word.tail.toLowerCase
      else word
    ).mkString(" ")
  }
  
  def main(args: Array[String]): Unit = {
    val text = "Hello world! This is a sample text for testing. Hello appears twice."
    
    println("Original:")
    println(text)
    
    println("\nWord count:")
    wordCount(text).foreach { case (word, count) =>
      println(s"$word: $count")
    }
    
    println(s"\nReverse words: ${reverseWords(text)}")
    
    val palindromes = List("A man a plan a canal Panama", "race a car", "hello")
    println("\nPalindrome test:")
    palindromes.foreach { str =>
      println(s"'$str' is palindrome: ${isPalindrome(str)}")
    }
    
    println(s"\nCapitalize words: ${capitalizeWords("hello world from scala")}")
  }
}

Template Engine

scala
object SimpleTemplateEngine {
  def render(template: String, variables: Map[String, String]): String = {
    variables.foldLeft(template) { case (result, (key, value)) =>
      result.replace(s"{{$key}}", value)
    }
  }
  
  def renderWithDefaults(template: String, variables: Map[String, String], defaults: Map[String, String] = Map.empty): String = {
    val allVars = defaults ++ variables
    val variablePattern = """\{\{(\w+)\}\}""".r
    
    variablePattern.replaceAllIn(template, m => {
      val varName = m.group(1)
      allVars.getOrElse(varName, s"{{$varName}}")  // Keep unfound variables
    })
  }
  
  def main(args: Array[String]): Unit = {
    val template = "Hello {{name}}, welcome to {{site}}! Your role is {{role}}."
    
    val variables = Map(
      "name" -> "Alice",
      "site" -> "Scala Tutorial"
    )
    
    val defaults = Map(
      "role" -> "student"
    )
    
    val result1 = render(template, variables ++ defaults)
    val result2 = renderWithDefaults(template, variables, defaults)
    
    println("Simple render:")
    println(result1)
    
    println("\nRender with defaults:")
    println(result2)
    
    // Missing variables case
    val incompleteVars = Map("name" -> "Bob")
    val result3 = renderWithDefaults(template, incompleteVars, defaults)
    println("\nMissing variables render:")
    println(result3)
  }
}

Config File Parser

scala
object ConfigParser {
  case class Config(properties: Map[String, String]) {
    def getString(key: String): Option[String] = properties.get(key)
    def getInt(key: String): Option[Int] = properties.get(key).flatMap(v => 
      try Some(v.toInt) catch { case _: NumberFormatException => None }
    )
    def getBoolean(key: String): Option[Boolean] = properties.get(key).map(_.toLowerCase == "true")
  }
  
  def parseConfig(configText: String): Config = {
    val properties = configText
      .split("\n")
      .map(_.trim)
      .filter(line => line.nonEmpty && !line.startsWith("#"))  // Filter empty lines and comments
      .flatMap { line =>
        line.split("=", 2) match {
          case Array(key, value) => Some(key.trim -> value.trim)
          case _ => None
        }
      }.toMap
    
    Config(properties)
  }
  
  def main(args: Array[String]): Unit = {
    val configText = 
      """# Database configuration
        |host=localhost
        |port=5432
        |database=myapp
        |username=admin
        |password=secret123
        |ssl_enabled=true
        |connection_timeout=30
        |
        |# Application settings
        |debug_mode=false
        |max_users=1000""".stripMargin
    
    val config = parseConfig(configText)
    
    println("Configuration parse result:")
    println(s"Host: ${config.getString("host").getOrElse("unknown")}")
    println(s"Port: ${config.getInt("port").getOrElse(0)}")
    println(s"SSL Enabled: ${config.getBoolean("ssl_enabled").getOrElse(false)}")
    println(s"Max Users: ${config.getInt("max_users").getOrElse(100)}")
    println(s"Debug Mode: ${config.getBoolean("debug_mode").getOrElse(false)}")
  }
}

Best Practices

  1. Use string interpolation: Prioritize s"$variable" instead of string concatenation
  2. Choose the right interpolator: s for general interpolation, f for formatting, raw for raw strings
  3. Performance considerations: Use StringBuilder or functional methods for extensive string operations
  4. Avoid null pointers: Use Option to handle potentially null strings
  5. Regular expressions: Use regular expressions for complex string matching
  6. Immutability: Strings are immutable, operations create new strings

Mastering string operations is fundamental to Scala programming, these techniques will be frequently used in actual development.

Content is for learning and research only.