diff --git a/README.md b/README.md index d5bc242..d7aaf88 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ wrong (hint: it should be 1!). ES6's `Array.from` tried to solve this, but that - Limit string to width (truncate/pad) - Unicode-aware string length - Unicode-aware substring +- Unicode-aware substr 🔥 Please note that this library is built for accuracy, not performance. It uses complex regular expressions to calculate the string length and perform other operations which are **not** particularly super-jawdropping-fast like @@ -29,7 +30,7 @@ And import it in your awesome node app: ```javascript // ES2015+ import * as stringz from 'stringz'; // OR: -import { limit, substring, length } from 'stringz'; +import { limit, substring, length, substr } from 'stringz'; // CommonJS var stringz = require('stringz'); @@ -86,6 +87,19 @@ length("Iñtërnâtiônàlizætiøn☃💩"); // 22 ```javascript substring("Emojis 👍🏽 are 🍆 poison. 🌮s are bad.", 7, 14); // "👍🏽 are 🍆" ``` +### Substr + function substr(str[, start[, end]]) + +| Param | Type | Default | Description | +|---|---|---|---| +| str | String | *none* | String to be devided | +| start | Number | Start of string | Start position | +| end | Number | String length minus `start` parameter | Length of result | + +#### Examples +```javascript +substr("A.C. Milan 🇮🇹⚽️", 5, 7); // "Milan 🇮🇹" +``` ## Test ```bash diff --git a/src/index.js b/src/index.js index c00bb63..ee2b049 100644 --- a/src/index.js +++ b/src/index.js @@ -28,6 +28,50 @@ export function substring(str, begin = 0, end) { return str.match(astralRange).slice(begin, end).join(""); } +export function substr(str, begin = 0, len) { + // Check for input + if (typeof str !== "string") { + throw new Error("Input must be a string"); + } + + const strLength = length(str); + + // Fix type + if (typeof begin !== "number") { + begin = parseInt(begin, 10); + } + + // Return zero-length string if got oversize number. + if (begin >= strLength) { + return ""; + } + + // Calculating postive version of negative value. + if (begin < 0) { + begin += strLength; + } + + let end; + + if (typeof len === "undefined") { + end = strLength; + } + else { + // Fix type + if (typeof len !== "number") { + len = parseInt(len, 10); + } + if (len >= 0) { + end = len + begin; + } + else { + end= begin; + } + } + + return str.match(astralRange).slice(begin, end).join(""); +} + export function limit(str, limit = 16, padString = "#", padPosition = "right") { // Input should be a string, limit should be a number if (typeof str !== "string" || typeof limit !== "number") { diff --git a/test/substr.test.js b/test/substr.test.js new file mode 100644 index 0000000..970c7c8 --- /dev/null +++ b/test/substr.test.js @@ -0,0 +1,34 @@ +import assert from "assert"; +import { substr } from "../src/index"; + +describe("Substr", () => { + const string = "Two things are infinite: the universe and human stupidity; and I'm not sure about the universe."; + const unicodeString = "دانشگاهی که دانشگاه نباشد، دانشگاه نیست."; + const emojiString = "Emojis 👍🏽 are 🍆 poison. 🌮s are bad."; + + it("Substrs latin text correctly", () => { + assert.strictEqual(substr("Iñtërnâtiônàlizætiøn☃", 0, 10), "Iñtërnâtiô"); + assert.strictEqual(substr(string, 25, 32), string.substr(25, 32)); + }); + + it("Substrs unicode text correctly", () => { + assert.strictEqual(substr(unicodeString, 0, 11), "دانشگاهی که"); + assert.strictEqual(substr(emojiString, 7, 7), "👍🏽 are 🍆"); + }); + + it("Substrs if arguments are unspecified", () => { + assert.strictEqual(substr(string, 10), string.substr(10)); + assert.strictEqual(substr(string, 120), string.substr(120)); + assert.strictEqual(substr(string, '1', '2'), string.substr('1', '2')); + assert.strictEqual(substr(string), string); + }); + + it("Substrs even with negative arguments", () => { + assert.strictEqual(substr(string, -4), string.substr(-4)); + assert.strictEqual(substr(string, -4, -1), string.substr(-4, -1)); + }); + + it("Throws an error if wrong arguments are specified.", () => { + assert.throws(() => substr(12, 1, 2), Error); + }); +});