Nim: Finding & extracting substrings | Glenn Gillen
Nim: Finding & extracting substrings

Nim: Finding & extracting substrings

Mar 21, 2022

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"]
Hi, I'm Glenn! 👋 I've spent most of my career working with or at startups. I'm currently the Director of Product @ 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 Cloud and 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.