Skip to Content
  • Website
Codsen
  • Home
  • Open Source
  • Articles
  • About

prevOpen Source→string-left-rightnext

string-left-right6.2.0

Looks up the first non-whitespace character to the left/right of a given index

Downloads per monthChangelogMIT Licenselibera manifesto
  • the top
  • Installation
  • Quick Take
  • Examples
  • PURPOSE
  • API — LEFT() AND RIGHT()
  • API — CHOMPLEFT()…
  • API — CHOMPLEFT()…
  • API — LEFTSEQ() AND…
  • API — LEFTSTOPATNE…
  • API — LEFTSTOPATRA…
  • API — VERSION
  • API — TYPES
  • MORE COMPLEX…
  • Changelog

Installation

Quick Take

Examples

  • Match a character sequence without regard to letter case
  • Match repeated sequences on the left and include nearby whitespace
  • Control how chomp functions include surrounding whitespace
  • Match repeated sequences on the right and include nearby whitespace
  • Match a whitespace-tolerant character sequence on the left
  • Combine optional and repeated sequence flags
  • Mark one sequence value as optional with a question mark
  • Match one or more repeated sequence values with an asterisk
  • Match a whitespace-tolerant character sequence on the right
  • Find the nearest non-whitespace character on the right
  • Treat a newline as a stopping point in either direction
  • Treat a raw non-breaking space as a stopping point

Purpose

It’s trivial to check, is something on the left or on the right of a given index in a string. That’s str[i - 1]/str[i + 1]. Done.

It’s not that trivial to check, what is the index of the first non-whitespace character on either side. You need to use loops or trim functions and calculate the position, also consider the null cases where there are no such characters.

That’s what this program is about — it is a string value lookup helper.

API — left() and right()

Both exported functions have the same API:

On both, the first input argument is a string, the optional second is a starting index. The functions “look” to the left or to the right of that index, then report a first non-whitespace character’s index on that side. If it’s absent, functions will return null.

The test for whitespace is truthy string.trim().length — the trimmed string must have length; otherwise, it’s a whitespace.

These functions allow you to locate the first non-whitespace character on left or right.

For example,

import { left } from "string-left-right";
// start at index 2, which is character "b".
const res = left("a b", 2);
// the first non-whitespace character to the left of "b" is "a", at index 0:
console.log(res);
// => 0

The output is either natural number index, pointing to the nearest non-whitespace character on either side or null (if the string ends further, for example).

API — chompLeft() and chompRight()

These two allow you to jump over certain repeated characters, possibly spaced out with whitespace.

For example, imagine you have this string:

text x  y xyyyyxxxx       x x x x x yyyy y y y .

Imagine, you are “located” at the index of dot “.", 47. In this case, chompLeft() lets you “jump” over x’s and y’s and locate the index of a second “t” in “text”, 3.

Both exported functions have the same API:

You can pass a plain object — options — as the third argument, or you can omit it.

For example:

import { chompLeft } from "string-left-right";
// this says: jump over all b's and c's when traversing left from "x",
// then report the index of a first non-whitespace string you landed upon (
// or leave space, depending on the chosen mode, see next chapter for its API)
const res1 = chompLeft("a  b c b c  x y", 12, "b", "c");
console.log(`res1`);
// => 2

// the default mode is 0 and it's omitted, so above example is the same as:
const res2 = chompLeft("a  b c b c  x y", 12, { mode: 0 }, "b", "c");
console.log(`res2`);
// => 2

API — chompLeft() and chompRight() modes

You can pass an options object as a third argument before characters to match.

Modes:

  • 0 — leave single space if possible
  • 1 — stop at first space, leave whitespace alone
  • 2 — aggressively chomp all whitespace except newlines (CRopens in a new tab, LFopens in a new tab)
  • 3 — aggressively chomp all whitespace including newlines (CRopens in a new tab, LFopens in a new tab)

For example:

import { chompLeft } from "string-left-right";
const res1 = chompLeft("a\n  b c b c  x y", 13, "b", "c");
console.log(res1);
// => 2
// the default chomp stopped when it reached line break character. It didn't leave a space because it's not a non-whitespace character. If it were not a line break but a letter, it would have stopped one space short of it.

// passing default { mode: 0 } is the same result:
const res2 = chompLeft("a\n  b c b c  x y", { mode: 0 }, 13, "b", "c");
console.log(res2);
// => 2

// mode 1 - stops at first space met, in this case at first "b"
const res3 = chompLeft("a\n  b c b c  x y", 12, { mode: 1 }, "b", "c");
console.log(res3);
// => 4
// PS. "\n" counts as length of one

// mode 2 - chomps all whitespace except newlines
// in this case it stops to the right of \n, index 2:
const res4 = chompLeft("a\n  b c b c  x y", 12, { mode: 2 }, "b", "c");
// => 2

// mode 3 - hungriest of all whitespace chomps - chomps until it meets
// edge of a string or non-whitespace character (one which String.trim()'s
// to non-zero length character):
const res5 = chompLeft("a\n  b c b c  x y", 12, { mode: 3 }, "b", "c");
// => 1

The chompRight() works the same way, just towards the right side of a given index.

API — leftSeq() and rightSeq()

leftSeq() and rightSeq() matches the characters in that order, on the particular side of given index, disregarding the whitespace.

Both exported functions have the same API:

Input argumentTypeObligatoryDescription
str
Type: String
Obligatory: yes
strStringyesString to work upon
idx
Type: Natural number or zero
Obligatory: yes
idxNatural number or zeroyesIndex at which to start looking on either side
opts
Type: Plain object
Obligatory: no
optsPlain objectnoThe Optional Options Object, see below for its API
str1ToMatch
Type: String, single character
Obligatory: no
str1ToMatchString, single characternoThe first character to match on the sequence
str2ToMatch
Type: String, single character
Obligatory: no
str2ToMatchString, single characternoThe second character to match on the sequence
str3ToMatch
Type: String, single character
Obligatory: no
str3ToMatchString, single characternoThe third character to match on the sequence
...
Type: String, single character
Obligatory: no
...String, single characternoThe n-th character to match on the sequence

Functions return null or a plain object (the SeqOutput type above):

You can put as many characters as you want.

Example:

import { leftSeq } from "string-left-right";
// start at index 5, that's "f", and look on the left, are there sequence
// of characters "c", "d" and "e", possibly separated by whitespace
const result = leftSeq("abcdefghijk", 5, "c", "d", "e");
// yes, and there are no gaps:
console.log(JSON.stringify(result, null, 4));
// => {
//      gaps: [],
//      leftmostChar: 2,
//      rightmostChar: 4
//    }

Now example with gaps:

Again starting on “f” and looking left, are the sequence “c”, “d”, “e” on that side?

const res = leftSeq("a  b  c  d  e  f  g  h  i  j  k", 15, "c", "d", "e");
console.log(res);
// => {
//      gaps: [
//        [7, 9],
//        [10, 12],
//        [13, 15],
//      ],
//      leftmostChar: 6,
//      rightmostChar: 12,
//    }

Program reports any whitespace gap ranges it encountered and also the indexes of the leftmost and the rightmost characters.

API — leftStopAtNewLines() and rightStopAtNewLines()

Both exported functions have the same API.

On both, the first input argument is a string, the optional second (marked by brackets above) is a starting index.

Both functions are the same as left()/right(), except that besides non-whitespace characters, they also stop at CR and LF, line break characters.

For example,

import { right, rightStopAtNewLines } from "string-left-right";
const str = "a \n\n\nb";
// right() does not stop at whitespace characters and linebreaks are
// whitespace characters:
const res1 = right(str, 0);
// rightStopAtNewLines() will also stop at line break characters:
const res2 = rightStopAtNewLines(str, 0);
console.log(`res1 = ${res1}; res2 = ${res2}`);
// res1 = 5; res2 = 2

PS. While you type Mac line ending LF as two characters, backwards slash and “n” — \n — it counts as one character.

API — leftStopAtRawNbsp() and rightStopAtRawNbsp()

Both exported functions have the same API.

The same as left()/right(), except they also stop at a raw non-breaking space (U+00A0opens in a new tab). A raw nbsp trims to nothing, so left()/right() skip over it; these two treat it as if it were a real character.

That matters when a non-breaking space is meaningful rather than incidental — as it is in detergent, where an already-placed   must not be stepped over while hunting for widow words.

import { right, rightStopAtRawNbsp } from "string-left-right";
// the string is "a", space, two raw nbsp's, space, "b":
const str = "a    b";

// right() skips all whitespace, raw nbsp included, and lands on "b":
console.log(right(str, 0));
// => 5

// rightStopAtRawNbsp() stops on the first raw nbsp instead:
console.log(rightStopAtRawNbsp(str, 0));
// => 2

API — version

You can import version:

API — types

This package is written in TypeScript and exports the type Opts, the Optional Options Object of leftSeq() and rightSeq():

KeyTypeDefaultDescription
i
Type: Boolean
Default: false
iBooleanfalseSet to true to match ignoring letter case.
import { leftSeq } from "string-left-right";

console.log(leftSeq("abCDefghijk", 5, "c", "d", "e"));
// => null

console.log(leftSeq("abCDefghijk", 5, { i: true }, "c", "d", "e"));
// => { gaps: [], leftmostChar: 2, rightmostChar: 4 }
import type { Opts } from "string-left-right";

The options object of chompLeft()/chompRight() — the one carrying mode — is a separate, internal type and is not exported.

More complex lookups

If you need more complex string lookups, check out string-match-left-right. It can trim whitespace or certain characters before matching.

Changelog

Open Changelog
↑ back to top
prev next

Copyright

All rights reserved © Roy Revelt 2026
All our open source packages are under MIT licenceopens in a new tab

Activities

🐛 See a bug? Raise an issueopens in a new tab
💘 Check out the Indiewebopens in a new tab and Libera manifestoopens in a new tab