string-left-right4.1.0

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

Quick Take

import { strict as assert } from "assert";
import {
  left,
  right,
  leftSeq,
  rightSeq,
  chompLeft,
  chompRight,
  leftStopAtNewLines,
  rightStopAtNewLines,
} from "string-left-right";

// get the closest non-whitespace character to the left of "d" (which itself
// is at string index 6)
const str = "abc   def";
//             |   |
//           012345678

assert.equal(
  `next non-whitespace character to the left of ${
    str[6]
  } (index 6) is ${str[left(str, 6)]} (index ${left(
    str,
    6
  )})`,
  "next non-whitespace character to the left of d (index 6) is c (index 2)"
);

Whole idea

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:

left(str, [idx])
right(str, [idx])

On both, the first input argument is a string, the optional second (marked by brackets above) is a starting index. We "look" to the left or to the right of that index, then report a first non-whitespace character's index on that side. In absence, we return null.

The determinator 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,

const { left } = require("string-left-right");
// we 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:

chompLeft(
  str, 
  idx, 
  [opts], 
  char1, 
  char2, 
  char3
)
chompRight(
  str, 
  idx, 
  [opts], 
  char1, 
  char2, 
  char3
)

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

For example:

const { chompLeft } = require("string-left-right");
// we're saying, 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:

For example:

const { chompLeft } = require("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:

leftSeq(
  str, 
  idx, 
  [opts], 
  str1ToMatch, 
  str2ToMatch, 
  str3ToMatch
)
rightSeq(
  str, 
  idx, 
  [opts], 
  str1ToMatch, 
  str2ToMatch, 
  str3ToMatch
)

Above, square brackets mean options are optional, you can omit them.

Input argument Type Obligatory? Description
str String yes String to work upon
idx Natural number or zero yes At which index we start looking on either side
opts Plain object no The Optional Options Object, see below for its API
str1ToMatch String, single character no The first character to match on the sequence
str2ToMatch String, single character no The second character to match on the sequence
str3ToMatch String, single character no The third character to match on the sequence
... String, single character no The n-th character to match on the sequence

You can put as many characters as you want.

Example:

const { leftSeq } = require("string-left-right");
// we 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:

We're also on "f" and we're also looking left, are the sequence "c", "d", "e" on that side.

t.same(
leftSeq("a b c d e f g h i j k", 15, "c", "d", "e"),
{
gaps: [
[7, 9],
[10, 12],
[13, 15],
],
leftmostChar: 6,
rightmostChar: 12,
},
"04.01.02"
);

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

API - leftStopAtNewLines() and rightStopAtNewLines()

Both exported functions have the same API.

leftStopAtNewLines(str, [idx])
rightStopAtNewLines(str, [idx])

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,

const { right, rightStopAtNewLines } = require("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.

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

See it in the monorepo opens in a new tab, on GitHub.

Contributing

To report bugs or request features or assistance, raise an issue on GitHub opens in a new tab.

Any code contributions welcome! All Pull Requests will be dealt promptly.

Licence

MIT opens in a new tab

Copyright © 2010–2021 Roy Revelt and other contributors

Related packages:

📦 string-match-left-right 7.1.0
Match substrings on the left or right of a given index, ignoring whitespace
📦 detergent 7.1.0
Extracts, cleans and encodes text
📦 string-character-is-astral-surrogate 1.13.0
Tells, is given character a part of astral character, specifically, a high and low surrogate
📦 string-strip-html 8.3.0
Strips HTML tags from strings. No parser, accepts mixed sources
📦 string-overlap-one-on-another 2.1.0
Lay one string on top of another, with an optional offset
📦 string-process-comma-separated 2.1.0
Extracts chunks from possibly comma or whatever-separated string
📦 string-unfancy 4.1.0
Replace all n/m dashes, curly quotes with their simpler equivalents