Scala - StringContext



StringContext in Scala works with string interpolation. StringContext includeS variables and expressions inside strings easily. It can also create custom ways to insert these variables and manage how these appear within strings. We will discuss StringContext in this post.

Introduction to StringContext

StringContext is a class in the Scala standard library. It creates interpolated strings. It is responsible for parsing and processing string literals that include embedded expressions. You can define custom interpolators which have flexibility and extend the capabilities of string interpolation.

1. Basic Operations

StringContext has various methods and properties that can be used to manipulate and construct strings dynamically. It is the backbone for the predefined interpolators (s, f, and raw) and for the creation of new ones.

Creating a StringContext

StringContext is automatically created when interpolated string is defined.

For example,

val name = "Scala"
val context = new StringContext("Hello, ", "!")
val result = context.s(name)
println(result)

The output will be,

Hello, Scala! 

Note that, to get the above output, you need to write the above code, like this:

object Main extends App {
  val name = "Scala"
  val context = new StringContext("Hello, ", "!")
  val result = context.s(name)
  println(result)
}

Static and Dynamic Parts

StringContext splits the interpolated string into static parts and dynamic arguments.

For example,

object Main extends App {
  val name = "Scala"
  val context = StringContext("Hello, ", "!")
  
  // Accessing static parts
  val staticParts = context.parts
  println("Static Parts:")
  staticParts.foreach(println)  
  
  // Accessing dynamic arguments
  val dynamicArgs = "Scala"
  println("\nDynamic Arguments:")
  println(dynamicArgs)  
}

The output will be,

Static Parts:
Hello, 
!

Dynamic Arguments:
Scala

2. Custom Interpolators

StringContext in Scala has the ability to define custom string interpolators. It provides specialized string processing capabilities.

Defining a Custom Interpolator

To create a custom interpolator, you need to define implicit class with the apply / unapply method. For example, creating a cap interpolator to capitalize embedded strings:

object Main extends App {
  implicit class CapInterpolator(val sc: StringContext) extends AnyVal {
    def cap(args: Any*): String = {
      val parts = sc.parts.iterator
      val expressions = args.iterator
      val sb = new StringBuilder
      while (parts.hasNext) {
        sb.append(parts.next())
        if (expressions.hasNext) {
          sb.append(expressions.next().toString.capitalize)
        }
      }
      sb.toString()
    }
  }

  val name = "scala"
  val hello = "hello"
  println(cap"$hello, $name")
}

The output will be,

Hello, Scala

Using Custom Interpolators

Once defined, custom interpolators can be used in the same way as the built-in ones. For example:

object CustomInterpolators {
  implicit class CapInterpolator(val sc: StringContext) extends AnyVal {
    def cap(args: Any*): String = {
      val parts = sc.parts.iterator
      val expressions = args.iterator
      val sb = new StringBuilder(parts.next())
      while (parts.hasNext) {
        sb.append(expressions.next().toString.capitalize)
        sb.append(parts.next())
      }
      sb.toString()
    }
  }
}

object Main extends App {
  import CustomInterpolators._

  val language = "scala"
  val website = "tutorialspoint"
  println(cap"I am learning $language from $website.")
}

The output will be,

I am learning Scala from Tutorialspoint.

Advantages of StringContext

  • Flexibility − StringContext can create and manage interpolated strings with custom behaviors and processing logic.
  • Extensibility − You can have custom interpolators in StringContext that expand string capabilities to meet specific needs.
  • Integration − You can integrate the Scala type system. So, it can have custom interpolators for compile-time checks and validations.
Advertisements