jackadull / stringish

String operations for non-string types.

Version Matrix


A small utility library that provides string-like operations for things that are not strings (and for strings, too). In this way, text-based algorithms can be abstracted to work not just on plain strings, but also on, for example, HTML.

Basically, the same thing that Scala's Numeric does for numbers. Except that the operations are modelled as individual types, one per operation. Not every string-ish type needs to be able to implement all of them.

By default, implementations for String and NodeSeq are provided. New implementations can be added easily.

Dependency management and compatibility

stringish is compatible with Scala 2.13. Best effort is made to always keep it up-to-date with the latest Scala version.

Cross-versioning will not be supplied. When a new Scala version is released, your code should be updated to that version as soon as possible anyways.


libraryDependencies += "net.jackadull" %% "stringish" % "1.1.0"




Here is an example method that would make a natural-language enumeration out of a sequence of parts. For example, given Seq("bell", "book", "candle") it would return "bell, book and candle":

import net.jackadull.stringish.{Concat, FromString}
def nlEnum[S](seq:Seq[S])(implicit concat:Concat[S], fromString:FromString[S]):S = seq match {
  case Seq() => fromString("")
  case Seq(single) => single
  case Seq(first, second) => concat(first, concat.sPlusX("and", second))
  case Seq(first, rest@_*) => concat(first, concat.sPlusX(", ", nlEnum(rest)))

As can be seen in the example, the string-like abstraction works by depending on an implicit operation parameter, and the concrete string-like type is left open.

Because the implicits for String and NodeSeq are provided by default, the method above will work out of the box with both of these types.

Aside from Concat and FromString, Stringish also provides the Capitalize operation, which buts the first letter of a string in upper case.

When all of those operations are provided for a certain type, it is useful to also provide the Stringish meta-operation. This is the equivalent to Numeric for numbers.

Implementing operations for other types

Adding further types to be supported by the Stringish operations is fairly easy: Just implement the Stringish operations that you would like to support, and provide implicit values for them. If you pull them in scope, either by putting them in the companion object, or with an import statement, all methods with Stringish operations will work with them just fine.

And remember: If you implement all of the Stringish operations, it may be a good idea to supply an implementation of the Stringish type itself as well.