This is a simple class that lets you navigate within a string. This is useful when creating simple tokenizers for instance.
Print each character in the string
import { StringWalker } from 'string-walker'
const str = 'My name is Pontus'
const s = new StringWalker(str)
while (!s.isEof()) {
console.log(s.currentChar())
s.next()
}
/*
Outputs:
M
y
n
a
m
e
i
s
P
o
n
t
u
s
*/
Tokenize a simple key/value file
Say we have a key/value file that allows for a syntax like:
key1: strvalue
key2 : 12
key3:some value
We don't care about the whitespace between the key, separator and value
import { StringWalker } from 'string-walker'
const str = `
key1: strvalue
key2 : 12
key3:some value`
const tokens: Array<{ type: string, value: string }> = []
const s = new StringWalker(str)
let state: 'key' | 'value' | 'none' = 'none'
while (!s.isEof()) {
// Consume whitespace
if (['\n', ' ', '\t'].includes(s.currentChar())) {
s.consume(['\n', ' ', '\t'])
}
switch (state) {
// When state is none we're expecting a key
case 'none': {
// Find the position of either space, tab or :
const end = s.findNextOf([' ', '\t', ':'])
// If end is NaN we got to the end of the string without finding
// what we are looking for
if (isNaN(end)) {
throw new Error('Syntax error')
}
// The key is located from the current position to `end`
const key = s.substring(s.position, end)
tokens.push({ type: 'key', value: key })
// Now move the cursor to where we found the character
s.moveTo(end)
state = 'key'
break
}
// When state is `key` we're expecting the next token to be a delimiter
case 'key': {
if (s.currentChar() !== ':') {
throw new Error(`Syntax error: Expected : got ${s.currentChar()}`)
}
tokens.push({ type: 'delimiter', value: ':' })
// Next we're expecting a value
state = 'value'
// Move the cursor to the next position
s.next()
break
}
case 'value': {
// The value should stretch to the end of the line
let end = s.findNext('\n')
// If end is NaN we've reached the end of the string
if (isNaN(end)) {
end = s.length
}
const val = s.substring(s.position, end)
tokens.push({ type: 'value', value: val })
s.moveTo(end)
// Now we're expecting either whitespace to the end or a new key
state = 'none'
break
}
// We should never get here
default:
throw new Error('Unknown stuff')
}
}
console.log(tokens)
/*
Expected output:
[
{ type: 'key', value: 'key1' },
{ type: 'delimiter', value: ':' },
{ type: 'value', value: 'strvalue' },
{ type: 'key', value: 'key2' },
{ type: 'delimiter', value: ':' },
{ type: 'value', value: '12' },
{ type: 'key', value: 'key3' },
{ type: 'delimiter', value: ':' },
{ type: 'value', value: 'some value' }
]
*/