Nim: Finding & extracting substrings

Nim: Finding & extracting substrings

Much like in Ruby, Nim treats strings as a sequence of chars. This means if you already know the positional value of the substring you want to access you can access it like an array (zero indexed):

var a = "Hello World!"
echo a[0]
# H

It also means you can supply a range to access more than a single char, having a slice returned:

var a = "Hello World!"
echo a[0 .. 4]
# Hello

In JavaScript/ECMAScript to work backwards from the end of the string means first determining the length of the string, which is also possible in Nim by calling len(str). However the recommended way to do it is using the ^ operator which is interpreted by the compile as the same thing, e.g.:

var a = "Hello World!"
echo a[0 .. ^1]
# Hello World!
# i.e., the whole strong

echo a[0 .. ^2]
# Hello World

echo a[^6 .. ^2]
# World

To check if a string contains a substring:

import strutils
var str = "Hello World!"
echo str.contains("World")
# true

To find the positional location of a substring:

import strutils
var str = "Hello World!"
echo str.find("World")
# 6

More advanced matching is possible via the std/strscans import. This is handly when you might ordinarily want to reach for regex, but want something a little more readable and expressive of intent. For example, this will extract integers that match the (int, int, int) format:

const input = "(1,2,4)"
var x, y, z: int
if scanf(input, "($i,$i,$i)", x, y, z):
  echo "matches and x is ", x, " y is ", y, " z is ", z
# matches and x is 1 y is 2 z is 4

Rather than instantiating those variables it’s also possible to use scanTuple to return a tuple of values:

let (success, year, month, day, time) = scanTuple("1000-01-01 00:00:00", "$i-$i-$i$s$+")
if success:
  assert year == 1000
  assert month == 1
  assert day == 1
  assert time == "00:00:00"

If you do need the power of regular expressions the std/re gives you access to the functions you’d expect:

import std/re
var matches: array[2, string]
if match("abcdefg", re"c(d)ef(g)", matches, 2):
  echo matches
  # ["d", "g"]

Published: 21/03/2022

Hi, I'm Glenn! 👋

I've spent most of my career working with or at startups. I'm currently the VP of Product / GTM @ Ockam where I'm helping developers build applications and systems that are secure-by-design. It's time we started securely connecting apps, not networks.

Previously I led the Terraform product team @ HashiCorp, where we launched Terraform 1.0, Terraform Cloud, and a whole host of amazing capabilities that set the stage for a successful IPO. Prior to that I was part of the Startup Team @ AWS, and earlier still an early employee @ Heroku. I've also invested in a couple of dozen early stage startups.