Code Monkey home page Code Monkey logo

node-stringbuilder's Introduction

StringBuilder for Node.js

CI

An easy and fast in-memory string builder for Node.js.

Code Example

const StringBuilder = require("node-stringbuilder");
const sb = new StringBuilder("Hi");
sb.appendLine(",").append("This is a simple example demonstrating how to use this module.");
console.log(sb.toString()); // Hi,
// This is a simple example demonstrating how to use this module.
sb.insert("Text can be added into any position of this builder.");
sb.replace(53, 118, "Or replace the existing text.");
console.log(sb.toString()); // Text can be added into any position of this builder.HOr replace the existing text.
sb.deleteCharAt(52).insert(52, " ");
console.log(sb.toString()); // Text can be added into any position of this builder. Or replace the existing text.
sb.toLowerCase().replaceAll("text", "string");
console.log(sb.toString()); // string can be added into any position of this builder. or replace the existing string.
console.log(sb.clone().reverse().toString()); // .gnirts gnitsixe eht ecalper ro .redliub siht fo noitisop yna otni dedda eb nac gnirts
console.log(sb.toString(0, 19)); // string can be added
console.log(sb.length()); // 86
console.log(sb.count()); // 15
console.log(sb.indexOf("is")); // Uint32Array [ 43, 72 ]
console.log(sb.indexOfSkip("is")); // Uint32Array [ 43, 72 ]
console.log(sb.lastIndexOf("is")); // Uint32Array [ 72, 43 ]
console.log(sb.indexOfRegExp(/is/g)); // { index: [ 43, 72 ], lastIndex: [ 45, 74 ] }
console.log(sb.repeat().indexOf("is")); // Uint32Array [ 43, 72, 129, 158 ]
sb.substring(11, 37);
console.log(sb.toString()); // be added into any position
console.log(sb.equalsIgnoreCase("be Added into Any position")); // true
console.log(sb.toBuffer()); // UTF-8 encoded

Features

  • Implemented with N-API.
  • Operating strings in a scalable buffer.
  • Multiple types of data are allowed to input.
    • Strings
    • Buffers(UTF-8 encoded)
    • Instances of this StringBuilder module
    • ReadStream(to read file)
    • Numbers, booleans, other objects
  • Fast string search algorithm(Boyer-Moore-MagicLen)
  • Clonable

Usage

Initiaiizing

Import this module by using require function.

const StringBuilder = require('node-stringbuilder');

Use new operator or from function to create a StringBuilder instance.

const sb1 = new StringBuilder();
// or 
const sb2 = StringBuilder.from();

When creating an instance of StringBuilder, you can initialize the text and capacity.

const sb = StringBuilder.from("First", 4096);

By default, a block of buffer space used by StringBuilder is 128 characters. The space of the buffer can be expanded or shrinked by blocks.

// To expand
const newCapacity = 65536;
sb.expandCapacity(newCapacity);
// To shrink
sb.shrinkCapacity();

If some text are added into StringBuilder, StringBuilder will check its space. And if the space is too small, it will re-alloc a bigger one automatically. This re-allocation has overheads, if it does this frequently, your program may be slowed down. Therefore, if you can predict the length of your text, please set the capacity when creating a StringBuilder instance.

Append

Concat text.

sb.append("string").append(123).append(false).append(fs.createReadStream(path));

Add a new line after append.

sb.appendLine("string");

Append text repeatedly.

sb.appendRepeat("string", 3);

Append a file asynchronizely.

await sb.appendReadStream(fs.createReadStream(path));

Insert

Insert text to any position.

sb.insert("string"); // To the head.
sb.insert(5, "string");

Replace

Replace text to the position in a range of index.

sb.replace(4, 15, "string");

Replace existing substrings to another.

sb.replacePattern("old", "new");
sb.replacePattern(
    "old",
    "new",
    offset,
    limit
);

Replace all existing substrings to another.

sb.replaceAll("old", "new");

Delete

Delete text from a range of index.

sb.delete(4, 15);

Delete a character at a index.

sb.deleteCharAt(4);

Clear all text, but preserve the capacity.

sb.clear();

Substring

Reserve text in a range of index.

sb.substring(1, 5); // input the start and end index
sb.substr(1, 5); // input the start index and length

Reverse

Reverse text.

sb.reverse();

Upper/Lower Case

Convert text to upper or lower case.

sb.upperCase();
sb.lowerCase();

Trim

Remove any leading and trailing whitespace.

sb.trim();

Repeat

Repeat current text for specific count.

sb.repeat(1);

Expand Capacity

Expand the capacity of this StringBuilder.

sb.expandCapacity(4096).append("string");

Expand and get the updated capacity,

const capacity = sb.expandCapacity(4096, true);

Shrink Capacity

Shrink the capacity of this StringBuilder.

sb.shrinkCapacity().clone().append("string");

Shrink and get the updated capacity,

const capacity = sb.shrinkCapacity(true);

Get Current Text Length

To get the length of this StringBuilder,

const length = sb.length();

Get Current Capacity

To get the length of this StringBuilder,

const capacity = sb.capacity();

Count the words

To count the words,

const words = sb.count();

Build String

Build a string of a specific range of index.

const str = sb.toString(4, 10);

Build a UTF-8 buffer of a specific range of index.

const buffer = sb.toBuffer(4, 10);

To get the full text,

const text = sb.toString();
const buffer = sb.toBuffer();

To get one character at a specific index,

const c = sb.charAt(4);

Search String

Search substrings from the head,

const indexArray = sb.indexOf("string");
const indexArray2 = sb.indexOf("string", offset, limit);

Search substrings from the head by using RegExp,

var indexArray = sb.indexOf(/string/g);

Search substrings from the end,

const indexArray = sb.lastIndexOf("string");

Equals

Determine whether the two strings are the same.

const equal = sb.equals("string");

To ignore the case of letters,

const equal = sb.equalsIgnoreCase("string");

Determine whether it starts or ends with a specific pattern.

const start = sb.startsWith("string");
const end = sb.endsWith("string");

RegExp is not supported in startsWith and endsWith methods.

Clone

Clone this StringBuilder.

const newSB = sb.clone();

Tests

To run the test suite, first install the dependencies, then run npm test:

npm install
npm test

Benchmark

To run the benchmark suite, first install the dependencies, then run npm run benchmark:

npm install
npm run benchmark

Here is my result,

Append
  - 43 milliseconds
  ✓ Natively append text 1000000 times (43ms)
  - 567 milliseconds
  ✓ Use StringBuilder to append text 1000000 times (567ms)
  - 1278 milliseconds
  ✓ Use StringBuilder to insert text 1000000 times at the end (1287ms)
  - 17 milliseconds
  ✓ Use StringBuilder to append text 1000000 times repeatly

Insert
  - 92 milliseconds
  ✓ Natively insert text 10000 times (92ms)
  - 10 milliseconds
  ✓ Use StringBuilder to insert text 10000 times

Delete
  - 1427 milliseconds
  ✓ Natively delete text 5000 times (1429ms)
  - 87 milliseconds
  ✓ Use StringBuilder to delete text 5000 times (88ms)

Replace
  - 1511 milliseconds
  ✓ Natively replace text 5000 times (1513ms)
  - 85 milliseconds
  ✓ Use StringBuilder to replace text 5000 times (86ms)

Replace Pattern
  - 37 milliseconds
  ✓ Natively replace text with the same length by using a RegExp pattern
  - 20 milliseconds
  ✓ Use StringBuilder to replace text with the same length by using a pattern
  - 35 milliseconds
  ✓ Natively replace text by using a RegExp pattern
  - 29 milliseconds
  ✓ Use StringBuilder to replace text by using a pattern

Equals
  - 2 milliseconds
  ✓ Natively check the equal 50000 times
  - 13 milliseconds
  ✓ Use StringBuilder to check the equal 50000 times

EqualsIgnoreCase
  - 21 milliseconds
  ✓ Natively check the equal 50000 times
  - 19 milliseconds
  ✓ Use StringBuilder to check the equal 50000 times

IndexOf
  - 65 milliseconds
  ✓ Natively search text (65ms)
  - 2 milliseconds
  ✓ Use StringBuilder to search text

Reverse
  - 516 milliseconds
  ✓ Natively reverse text (516ms)
  - 14 milliseconds
  ✓ Use StringBuilder to reverse text

According to the result of benchmark, if you just want to append a few different strings, please append them by using native operator + instead of this module.

License

MIT

node-stringbuilder's People

Contributors

magiclen avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

node-stringbuilder's Issues

C4244 compiler warnings: type conversions causing possible loss of data

As pointed out in a closed issue, compiling for electron using:
node-gyp rebuild --target=3.0.6 --arch=x64 --dist-url=https://atom.io/download/electron
causes many C4244 warnings.

These seem benign, as the compiler does implicit type conversions.
I nevertheless suppressed these warnings by using casts in the code for node-stringbuilder.c
eg: buffer[resultListLength++] = (uint32_t)starePointer + 1; // approx line 73
buffer[resultListLength++] = (uint32_t)starePointer + 1; // approx line 133
buffer[resultListLength++] = (uint32_t)sourcePointer + 1; // approx line 250
int64_t log2Floor(int64_t n) {return (int64_t) (floor(log2((double)n))); // approx line 488
int64_t addedLength = (int64_t) pow((double)2, (double)(i - 1)) * contentBufferLength; // 848
int64_t realAddedCount = (int64_t)pow((double)2, (double)log2Count); // approx 851
int64_t addedLength = (int64_t)pow((double)2,(double)( i - 1)) * originalLength; // approx 1188
int64_t realAddedCount = (int64_t)pow((double)2, (double)log2Count); // approx 1191

But these explicit casts are probably not necessary, and whether they'd impact on performance anyway I'm not sure.

node-gyp build and npm install both fail

I've tried to install using npm install node-stringbuilder and also I've tried building with node-gyp using node-gyp configure build.

I'm using [email protected] and [email protected]
Not sure if that is an issue there.

In both cases the builds fail with these messages:

c:\node-stringbuilder\node_modules\node-stringbuilder\src\node-stringbuilder.c(6): warning C4005: 'max': macro redefinition [c:\node-stringbuilder\node_modules\node-stringbuilder\build\node-stringbuilder.vcxpro
j]
c:\program files (x86)\windows kits\10\include\10.0.17134.0\ucrt\stdlib.h(1289): note: see previous definition of 'max'

c:\node-stringbuilder\node_modules\node-stringbuilder\src\node-stringbuilder.c(1315): error C2057: expected constant expression [c:\node-stringbuilder\node_modules\node-stringbuilder\build\node-stringbuilder.vc
xproj]
c:\node-stringbuilder\node_modules\node-stringbuilder\src\node-stringbuilder.c(1315): error C2466: cannot allocate an array of constant size 0 [c:\node-stringbuilder\node_modules\node-stringbuilder\build\node-s
tringbuilder.vcxproj]
c:\node-stringbuilder\node_modules\node-stringbuilder\src\node-stringbuilder.c(1315): error C2133: 'utf8Data': unknown size [c:\node-stringbuilder\node_modules\node-stringbuilder\build\node-stringbuilder.vcxpro
j]

Replace from an array of strings

It would be useful if the ReplaceAll method could accept an array.

As an example, I altered the ReplaceAll code to produce this:
// from javascript call as: sb.replaceFromArray()

napi_value ReplaceFromArray(napi_env env, napi_callback_info info){
size_t argsLength = 1;
napi_value args[2]; // will hold parameters from a 2d array during a for loop
napi_value me;
int n;

	// test with hard-coded array containing 2 pairs of strings
	//  "john is some writer"  => "john is this joke"
    const char* arr[][2] = {{"some", "this"},
		                    {"writer", "joke"}};

   
    napi_get_cb_info(env, info, &argsLength, args, &me, 0);  // place input parameters into args[]
    /* if (argsLength < 2){  // this bit no longer needed
         return me;
   */
    uint16_t* buffer;
    int64_t* metadata;
    getBufferAndMetaData(env, me, &buffer, &metadata);
    uint16_t* pattern;
    int64_t patternLength;
    bool patternFreeAble;
    for (n = 0; n < 2;  n++ )    
	{
	 	napi_create_string_utf8(env, arr[n][0],
                                 NAPI_AUTO_LENGTH ,
                                 &args[0]);

		napi_create_string_utf8(env, arr[n][1],
                                 NAPI_AUTO_LENGTH ,
                                 &args[1]);
              // .....  the rest of the replaceAll code
            }
        return me;

}

I also note that the main section from replaceAll is mostly identical to that inside the ReplacePattern function. There is a potential therefore for refactoring, by which this section could be called from a separate function.

A more sophisticated implementation of ReplaceFromArray() would pass the array as a parameter, although embedding a hard-coded array has the advantage of "hiding" the array contents, while still suiting many possible applications.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.