← All modules

Distribution · text

String::Utils

Works

About forty small string routines that the core does not have — substring-before and -after, accent stripping, n-grams, abbreviations, whitespace introspection — each one a sub rather than a method.

Version
0.0.40 zef:lizmat
Depends
none beyond the core
License
Artistic-2.0
Its own test suite
3 files, green
Checked
2026-09-16 against Raku++ 3.28.0 and Rakudo 2026.08
Where it lives
raku.land · source

Install it #

$ rakupp install String::Utils

zef install String::Utils writes the same store; either installer leaves the module usable by both engines.

What it is for #

Every one of these is a line or three of Raku you have written before. The value is not that they are hard; it is that they are named, so a program says before($path, '/') instead of $path.substr(0, $path.index('/')) and stops being wrong when the separator is absent.

The distribution exports about forty of them. This page covers the families rather than the list.

Cutting a string at a marker #

File
use String::Utils;

my $path = 'lib/String/Utils.rakumod';
say 'before   : ', before($path, '/').raku;
say 'after    : ', after($path, '/').raku;
say 'between  : ', between($path, 'lib/', '.rakumod').raku;
say '';
say 'stem           : ', stem('archive.tar.gz').raku;
say 'stem, 1 part   : ', stem('archive.tar.gz', 1).raku;
say 'shorten        : ', shorten('a rather long sentence', 10).raku;
say 'nomark         : ', nomark('çédille naïve').raku;
say 'is-sha1        : ', is-sha1('0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33');
say '';
say 'ngram("raku", 2) : ', ngram('raku', 2).join(' ');
say 'word-at          : ', word-at('the quick brown', 4).raku;
say 'abbrev("length") : ', abbrev('length').sort(*.key).map({ .key }).join(' ');
Output
before   : "lib"
after    : "String/Utils.rakumod"
between  : "String/Utils"

stem           : "archive"
stem, 1 part   : "archive.tar"
shorten        : "a ra…tence"
nomark         : "cedille naive"
is-sha1        : False

ngram("raku", 2) : ra ak ku
word-at          : (4, 5, 1)
abbrev("length") : l le len leng lengt length

before, after and between return Nil when the marker is not there, which is the behaviour that makes them worth using: the .substr/.index version returns nonsense or throws, and the difference only shows up on the input you did not test.

stem strips extensions and takes a count — one call for archive and one for archive.tar, which is the distinction .extension cannot make. shorten elides in the middle with , keeping both ends, because the ends are where the information is in a path or an identifier.

nomark strips diacritics without a normalisation table lookup on your side, which is what you want before a case-insensitive compare or a slug.

Sequences and prefixes #

ngram slices a string into overlapping runs — the input to a similarity measure or a cheap index. word-at answers where the word under a character offset starts and how long it is, which is the primitive an editor needs and nothing in core provides.

abbrev returns every unambiguous prefix of a word, as a Hash mapping prefix to full word. The hash is the reason the example sorts before printing: the return value has no order, so a program that joins it directly prints something different on every run, and on two engines at once.

Where the two engines differ #

Nowhere. Every routine above produced identical output on Raku++ and Rakudo, and all three test files pass on both.

The one thing to watch is the abbrev ordering above, and it is not an engine difference — it is a Hash being asked to behave like a list. Sort it, or index it, but do not iterate it and expect a sequence. That is also the reason this page's example is stable under the site's two-runs-per-engine check, and an earlier draft of it was not.