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);
+ });
+});