14 KiB
str : An interactive string manipulation environment
Copyright (C) 2026 Garrett Mills shout@garrettmills.dev
Syntax Overview
String manipulation operations are performed on a "subject" -- a given string you are working on.
Most of the time, you do this by pasting a string into the interpreter, then running a series of statements that make some changes to the string. Here's an example where a few lines of a TSV file have been pasted in as the subject:
str %> paste
┌───────────────
│ 0 │Mazda RX4 21 6 160 110 3.9 2.62 16.46 0 1 4 4
│ 1 │Mazda RX4 Wag 21 6 160 110 3.9 2.875 17.02 0 1 4 4
│ 2 │Datsun 710 22.8 4 108 93 3.85 2.32 18.61 1 1 4 1
│ 3 │Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1
│ 4 │Hornet Sportabout 18.7 8 360 175 3.15 3.44 17.02 0 0 3 2
├───────────────
│ :: string
└───────────────
str %>
Statements in str take the form of <command> [...args]. For a trivial example, here we use a
command to replace all instances of Hornet with Foobar:
str %> replace Hornet Foobar
┌───────────────
│ 0 │Mazda RX4 21 6 160 110 3.9 2.62 16.46 0 1 4 4
│ 1 │Mazda RX4 Wag 21 6 160 110 3.9 2.875 17.02 0 1 4 4
│ 2 │Datsun 710 22.8 4 108 93 3.85 2.32 18.61 1 1 4 1
│ 3 │Foobar 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1
│ 4 │Foobar Sportabout 18.7 8 360 175 3.15 3.44 17.02 0 0 3 2
├───────────────
│ :: string
└───────────────
str %>
Notice that I did not have to quote the strings Hornet and Foobar because they do not contain any
special syntax characters. The only special syntax characters in str are single quotes themselves ('),
whitespace, and opening parens (().
Commands are separated either by newlines (pressing enter), or using the ; separator. For example:
┌───────────────
│ 0 │foo bar baz
├───────────────
│ :: string
└───────────────
str %> replace oo OO; replace ba BA
┌───────────────
│ 0 │fOO BAr BAz
├───────────────
│ :: string
└───────────────
str %>
Comments start with -- and run through the end of the line. Example:
str %> = abc -- my comment
┌───────────────
│ 0 │abc
├───────────────
│ :: string
└───────────────
str %>
Data Types
:: string- Strings. Does what it says on the tin.:: int- Base-10 integers (e.g. for use as offsets).:: destructured- A list split by some value (e.g.foo::barsplit on::).- These differ from normal lists in that they keep track of their "connective tissue".
- For example,
foo::barsplit on::will give you[foo, bar], but will remember thatbaris prefixed with:: - This allows you to
jointhe destructured back together later on
:: ... :: ()- Lambdas. Multi-parameter functions. See "Working with Lambdas" below.
Available Commands
I/O & Editor Control
exit
Stop str and exit. This can also be done with ^C.
paste
Replace the current subject with the current contents of your clipboard.
copy
Copy the current subject to your clipboard.
infile <path>
Replace the current subject with the contents of the given file.
Example: infile ~/foo.txt
outfile <path>
Write the current subject to the given file (replacing its current contents).
Example: outfile ~/foo.txt
assign <value> / = <value>
Replace the current context with the given value.
Example: = 'foo bar' -> foo bar
Example: = $a -> (value of $a)
clear
Clear the current subject (replace it with an empty string).
show
Print the current subject. This is done by default after every operation.
undo
Undo the last statement/operation.
redo
Redo the last undone statement/operation.
history
Show a log of recent statements/operations.
edit
Open the current subject in an external text editor (specified by $EDITOR).
Once you save and close the editor, the modified contents will be loaded back into str.
A crutch.
save [<statefile>]
Save the current state of the str session to the given statefile (default ~/.str.json).
load [<statefile>]
Restore a str session from a saved state file (default ~/.str.json).
runfile <path>
Execute the contents of the given file as a series of str commands.
script <path> [...<args>]
Execute an external script and replace the current subject with the returned output.
The current subject is passed as the first argument, followed by the optional additional args.
Basic String Operations
enclose [<with>]
Wrap the string on either side with the given string (default = ().
If the string is one half of a matching pair (e.g. (, [, {, &c), surround with the matching pair.
Example: foo -> enclose [ -> [foo]
lower
Convert the string to lower-case.
Example: FoO -> lower -> foo
upper
Convert the string to upper-case.
Example: FoO -> upper -> FOO
lsub <offset> [<length>]
Take a left-substring starting at the given offset. Stop after the given length, if provided.
Example: abcdef -> lsub 1 3 -> bcd
rsub <offset> [<length>]
Take a right-substring starting at the given offset. Stop after the given length, if provided.
Example: abcdef -> rsub 1 3 -> cde
prefix <with>
Prefix the current subject with the given string.
Example: bar -> prefix foo -> foobar
suffix <with>
Suffix the current subject with the given string.
Example: foo -> suffix bar -> foobar
quote [<with>]
Quote the string with the given quotemark (default ').
If the string is already quoted with a standard quotemark, strip it off first.
Example: 'bar' -> quote " -> "bar"
unquote [<with>]
Unquote the string if it is quoted with a standard quotemark (or with, if provided explicitly).
Example: "foo" -> unquote -> foo
replace <find> <with>
Replace all instances of find with the given with.
Example: foobaz -> replace baz bar -> foobar
rev
Reverse the given string (or destructured list).
Example: abcdef -> rev -> fedcba
trim [<type>] [<char>]
Trim leading/trailing instances of char from the subject (by default, any whitespace).
By default, trim uses the both type, but supports the following modes:
start/left- only from the start of the stringend/right- only from the end of the stringboth- from both start and end of the stringlines- remove any empty lines
Example: foo -> trim left -> foo
Example: fffubarfff -> trim both f -> ubar
indent <space|tab> [<level>]
Reindent the current subject with tabs or spaces.
If a level is provided, adjust the indentation to that level.
Example: word -> indent tab -> \tword
concat [...<strings>]
Replace the current subject with the result of concatenating the provided strings together.
Mostly useful in conjunction with variables.
Example: concat foo bar -> foobar
Multi-part Manipulation (line-wise, word-wise, destructured)
line ...<subcommand>
Execute the given subcommand on every line of the subject.
Example: foo\nbar -> line prefix -- -> --foo\n--bar
word ...<subcommand>
Execute the given subcommand on every word of the subject, preserving whitespace.
Example: foo bar baz -> word prefix -- -> --foo --bar --baz
each ...<subcommand>
Execute the given subcommand on every part of a destructured subject.
Example: [foo, bar, baz] -> each prefix A -> [Afoo, Abar, Abaz]
on <word|line|index> <index> ...<subcommand>
Execute the given subcommand on the specified word/line/index from the current subject.
word and line apply to strings that have not been destructured.
index is applied for destructured subjects. For destructured subjects you may omit the type (e.g. on 4 ...).
Example: foo bar baz -> on word 1 rsub 1 -> foo ba baz
drop <word|line|index> <index>
Delete the specified word/line/index from the current subject.
word and line apply to strings that have not been destructured.
index is applied for destructured subjects. For destructured subjects you may omit the type (e.g. drop 4).
Example: foo bar baz -> drop word 1 -> foo baz
take <word|line|index> <index>
Keep only the specified word/line/index from the current subject.
word and line apply to strings that have not been destructured.
index is applied for destructured subjects. For destructured subjects you may omit the type (e.g. take 4).
Example: foo bar baz -> take word 1 -> bar
contains <find>
If the subject contains the given substring, keep it. Otherwise, replace it with an empty string.
Most often used in conjunction with line, word, or each for filtering.
Example: afoo \n bfoo \n cbar -> line contains foo -> afoo \n bfoo \n
missing <find>
If the subject contains the given substring, replace it with an empty string. Otherwise, keep it.
Most often used in conjunction with line, word, or each for filtering.
Example: afoo \n bfoo \n cbar -> line missing foo -> \n \n cbar
lines
Destructure the current subject into individual lines.
Example: foo \n bar -> lines -> [foo, bar]
words
Destructure the current subject into individual words.
Example: foo bar \n baz -> words -> [foo, bar, baz]
split <on> [<limit>]
Destructure the current subject based on the given delimiter.
If a limit is provided, split the subject no more than the given number of times.
Example: foo::bar::baz::ban -> split :: 2 -> [foo, bar, baz::ban]
join [<on>]
Join the current destructured subject back together using the given delimiter.
If no delimiter is provided, it will preserve the existing delimiters between substrings.
If string is not destructured, joins the lines in the string.
Example: [foo, bar] -> join :: -> foo::bar
chunk <every> <line|word|char>
Destructure the current subject into chunks based on every Nth line/word/character.
Example: a b c d e f -> chunk 2 word -> [a b, c d, e f]
group <callable>
Group the current destructured subject based on some mapped value.
The callable is called for each destructured part and parts are bucketed together by the output value.
Example: [aa, ab, ba, bb] -> group (rsub 1) => [[aa, ab], [ba, bb]]
sort [<asc|desc>]
Sort the items in the destructured subject alphabetically either ascending (default) or descending.
If string is not destructured, sorts the lines in the string.
Example: [foo, bar] -> sort -> [bar, foo]
unique
Filter out duplicate values from the destructured subject.
If string is not destructured, filters out duplicate lines in the string.
Example: [foo, bar, foo] -> unique -> [foo, bar]
zip <with>
Interleave the current destructured subject with the given other destructured subject.
Example: Say $a is [1, 2, 3] and subject is [a, b, c] -> zip $a -> [a, 1, b, 2, c, 3]
Working with Variables
Variables in str start with a dollar sign and may be alphanumeric with underscores (e.g. $my_var).
Assign a variable using the standard syntax: $a = 'mystr'
You can then use them anywhere you may use a string: split $a
There are also several commands for interactive with variables, defined below.
to <var>
Store the current subject into the given variable.
Example: foo bar -> to $a
from <var>
Replace the current subject with the value of the given variable.
Example: from $a
set <var> <value>
Alternative syntax for variable assignment.
Example: set $a 'mystr' is equivalent to $a = 'mystr'
over <var> ...<subcommand>
Execute the given subcommand against the contents of var instead of the current subject.
Example: over $a replace foo bar
Working with Lambdas (functions, closures, &c)
str supports Lambda functions. These are defined as a series of commands which may optionally
have some number of parameters. For example:
$myReplacer = (|$a $b| split $a; join $b)
This trivial lambda takes two parameters, splits the subject on $a and joins it back together on $b (effectively, replace).
You may omit the parameter list if the lambda takes no parameters. For example, this basic TSV parser:
$myTSVParser = (
trim;
trim lines;
lines;
each split \t
)
call <lambda> [...<params>]
Execute the given lambda with the provided parameters, replacing the current context with the result.
Example: call $myReplacer foo bar
call operates over the current context. However, you can execute lambdas over the contents of a variable using over:
str %> $a = 'foo bar'
str %> over $a call $myReplacer foo bar
call also supports partial application. For example:
str %> over $myFooReplacer call $myReplacer foo
You can then call the partially-applied lambda with the remaining parameter(s):
str %> call $myFooReplacer bar
Misc
lipsum <num> <word|line|para>
Replace the current subject with "Lorem ipsum..." placeholder text.
Can generate individual words, lines, or paragraphs.
Example: lipsum 4 word -> lorem ipsum dolor sit
User-specific setup files
The file ~/.str.rc is automatically executed when str starts up.
You can use this to define a user-specific environment.