What is ranges-apply?
The 'ranges-apply' npm package is used to apply multiple string editing operations, defined as ranges, to a given input string. This is particularly useful for tasks that involve multiple, non-overlapping edits to a string, such as text processing, code formatting, or data cleaning.
What are ranges-apply's main functionalities?
Apply Ranges
This feature allows you to apply multiple ranges of edits to a string. Each range is defined by a start index, an end index, and a replacement string. The function processes these ranges and applies the edits to the input string.
const { rApply } = require('ranges-apply');
const input = 'Hello, world!';
const ranges = [
[7, 12, 'universe'],
[0, 5, 'Hi']
];
const result = rApply(input, ranges);
console.log(result); // 'Hi, universe!'
Handling Overlapping Ranges
This feature demonstrates how the package handles overlapping ranges. The edits are applied in the order they appear in the array, which can result in overlapping changes being concatenated.
const { rApply } = require('ranges-apply');
const input = 'Hello, world!';
const ranges = [
[7, 12, 'universe'],
[10, 15, 'planet']
];
const result = rApply(input, ranges);
console.log(result); // 'Hello, universeplanet!'
Empty Ranges
This feature shows how to insert text at a specific position without removing any existing characters. An empty range (where the start and end indices are the same) allows you to insert text at that position.
const { rApply } = require('ranges-apply');
const input = 'Hello, world!';
const ranges = [
[7, 7, 'beautiful ']
];
const result = rApply(input, ranges);
console.log(result); // 'Hello, beautiful world!'
Other packages similar to ranges-apply
diff-match-patch
The 'diff-match-patch' package provides robust algorithms for synchronizing plain text. It can be used to find differences between texts, patch texts, and apply patches. Compared to 'ranges-apply', it offers more advanced diffing and patching capabilities but may be more complex to use for simple range-based edits.
string-replace-async
The 'string-replace-async' package allows for asynchronous string replacements using regular expressions. While it focuses on regex-based replacements rather than range-based edits, it can be useful for more complex text processing tasks that require asynchronous operations.
replacestream
The 'replacestream' package is used for streaming text replacements. It is particularly useful for processing large files or streams of data. Unlike 'ranges-apply', which works on static strings, 'replacestream' is designed for use cases involving streams and large-scale text processing.
ranges-apply
Take an array of string slice ranges, delete/replace the string according to them
[![Test in browser][runkit-img]][runkit-url]
Table of Contents
Install
npm i ranges-apply
const replaceSlicesArr = require("ranges-apply");
import replaceSlicesArr from "ranges-apply";
Here's what you'll get:
Type | Key in package.json | Path | Size |
---|
Main export - CommonJS version, transpiled to ES5, contains require and module.exports | main | dist/ranges-apply.cjs.js | 3 KB |
ES module build that Webpack/Rollup understands. Untranspiled ES6 code with import /export . | module | dist/ranges-apply.esm.js | 3 KB |
UMD build for browsers, transpiled, minified, containing iife 's and has all dependencies baked-in | browser | dist/ranges-apply.umd.js | 3 KB |
⬆ back to top
Idea
Let's say you want to delete bunch of characters from a string and also to replace some. Technically, this means you need to mark the indexes of the characters where you start deletion and where you end.
For example, in this string, "a" has index 7
and "e" has index 14
.
some example text
^ || |^ |
0123456789|11|14|
10|13|16
12 15
If you want to do something to the word "example" above, that's indexes 5
and 12
. You can easily see them if you select the string - good code editors will report the index of the end of the selection in the status bar. Like Atom for example:
That's two numbers to put into an array. They mark a slice of string. Let's add a third element into that array - what to put instead. If it's blank, nothing will be added (it becomes a deletion operation), if it's a non-empty string, it will be inserted insted of the deleted characters (it becomes a replacement operation).
[
[10, 15],
[18, 20, "replace with this"]
];
Now what happens when you have a few slices? You put them into a parent array.
This library consumes such parent array and does the actual job crunching your string according to the list of slices.
Now, let's do it practically. Slice ranges match String.slice()
indexing, so you can always check is the slice you want correspond to the indexes you've got.
const repl = require("ranges-apply");
let str = "aaa delete me bbb and me too ccc";
console.log("slice 1: >>>" + str.slice(4, 13) + "<<<");
console.log("slice 2: >>>" + str.slice(18, 28) + "<<<\n");
str = repl(str, [[4, 13, "zzz"], [18, 28, "yyy"]]);
console.log("str = " + str);
If you omit the third argument, that slice will be deleted.
Slice ranges can be the same index. In that case, if there is third argument, its value will be inserted before the string at given index. If there's no third argument, nothing will happen.
⬆ back to top
API
stringReplaceSlicesArray(inputString, rangesArray);
Returns a string with requested slices deleted/replaced.
inputString
Type: string
- the string we want to work on.
rangesArray
Type: array
- the array of zero or more arrays containing a range and an optional replacement string.
For example,
[
[10, 15],
[18, 20, "replace with this"]
];
PSST. Check out ranges-push which helps to manage the rangesArray
. It has methods to add and retrieve the slices. Also, it helps in cases where slices overlap and helps to maintain the order of index ranges (it always goes from smallest to largest index, everywhere).
⬆ back to top
The algorithm
The plan is simple - we array.reduce
your given ranges array, slicing the input string accordingly.
The main thing is unit tests and edge case scenarios. Also, fancy optional features (upcoming) like using character enumeration counting emoji as one character.
⬆ back to top
In my case
Originally this library was part of email-remove-unused-css, where I traversed HTML as a string and compiled an array of things to delete or replace later, in one go. The performance was important, so it was not a good idea to delete/replace things on the spot because each deletion slowed down the process. Instead, I traversed the string, compiled this to-do array, then did the deletion/replacement on the whole thing, once. This appears to be the fastest way.
I'm going to use this library in all my HTML processing libraries who work on HTML as on string, without parsing it.
⬆ back to top
Contributing
-
If you want a new feature in this package or you would like us to change some of its functionality, raise an issue on this repo.
-
If you tried to use this library but it misbehaves, or you need advice setting it up, and its readme doesn't make sense, just document it and raise an issue on this repo.
-
If you would like to add or change some features, just fork it, hack away, and file a pull request. We'll do our best to merge it quickly. Prettier is enabled, so you don't need to worry about the code style.
⬆ back to top
Licence
MIT License (MIT)
Copyright © 2018 Codsen Ltd, Roy Revelt