Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ const count = stringzy.analyze.wordCount('Hello world'); // 2
- [patternCount](#patterncount) - calculates the number of times a specific pattern occurs in a given text
- [vowelConsonantCount](#vowelconsonantcount) - Counts the number of vowels and consonants in a given string
- [checkMultiplePatterns](#checkmultiplepatterns) - Finds occurrences of multiple patterns within a given text using Rabin–Karp algorithm (case sensitive)
- [checkSubsequence](#checksubsequence) - Checks whether the second string is a subsequence of the first string (case sensitive)

### Formatting

Expand Down Expand Up @@ -993,6 +994,37 @@ checkMultiplePatterns('hello world', ['xyz', '123']);
| text | string | required | The text to search within. |
| patterns | string\[ ] | required | An array of patterns to search for (each must be a string). |

#### <a id="checksubsequence"></a>checkSubsequence(str, sub)

Checks whether a given string sub is a subsequence of another string str.
A subsequence maintains the relative order of characters, but they do not need to be consecutive.
Case-sensitive comparison is performed.
Spaces and all characters are treated literally.

```javascript
isSubsequence('abcde', 'ace');
// true → 'a', 'c', 'e' appear in order

isSubsequence('abracadabra', 'aaa');
// true → multiple 'a's in correct order

isSubsequence('abcde', 'aec');
// false → order is broken (e comes before c)

isSubsequence('anything', '');
// true → empty subsequence is always valid

isSubsequence('AbC', 'AC');
// true → exact case matches

isSubsequence('a b c', 'abc');
// false → spaces count as characters
```
| Parameter | Type | Default | Description |
| --------- | ------ | -------- | ----------------------------------------------- |
| str | string | required | The main string to check within. |
| sub | string | required | The subsequence string to verify against `str`. |


---

Expand Down
33 changes: 33 additions & 0 deletions src/analyzing/checkSubsequence.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/**
* Checks whether the second string is a subsequence of the first string.
*
* A subsequence means all characters of the second string appear in the first string
* in the same relative order, but not necessarily consecutively.
*
* Is case sensitive
*
* @param {string} str1 - The string to check against.
* @param {string} str2 - The candidate subsequence.
* @returns {boolean} True if str2 is a subsequence of str1, otherwise false.
* @throws {TypeError} If either input is not a string.
*/
export function checkSubsequence(str1: string, str2: string): boolean {
if (typeof str1 !== "string" || typeof str2 !== "string") {
throw new TypeError("Both inputs must be strings");
}

// empty subsequence is always valid
if (str2 === "") return true;

let i = 0; // pointer for str2 (the subsequence)
let j = 0; // pointer for str1 (the main string)

while (i < str2.length && j < str1.length) {
if (str2[i] === str1[j]) {
i++;
}
j++;
}

return i === str2.length;
}
5 changes: 4 additions & 1 deletion src/analyzing/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export { stringSimilarity } from './stringSimilarity';
export { patternCount } from './patternCount';
export { vowelConsonantCount } from './vowelConsonantCount';
export { checkMultiplePatterns } from './checkMultiplePatterns';
export { checkSubsequence } from './checkSubsequence';

export { functionWordCount } from './functionWordCount';
export { contentWordCount } from './contentWordCount';
Expand All @@ -21,6 +22,7 @@ import { stringSimilarity } from './stringSimilarity';
import { patternCount } from './patternCount';
import { vowelConsonantCount } from './vowelConsonantCount';
import { checkMultiplePatterns } from './checkMultiplePatterns';
import { checkSubsequence } from './checkSubsequence';



Expand All @@ -33,5 +35,6 @@ export const analyzing = {
stringSimilarity,
patternCount,
vowelConsonantCount,
checkMultiplePatterns
checkMultiplePatterns,
checkSubsequence
};
35 changes: 35 additions & 0 deletions src/tests/analyzing/checkSubsequence.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { describe, it } from 'node:test';
import assert from 'node:assert';
import { checkSubsequence } from '../../analyzing/checkSubsequence';

describe('checkSubsequence', () => {
it('returns true for valid subsequences', () => {
assert.strictEqual(checkSubsequence('abcde', 'ace'), true);
assert.strictEqual(checkSubsequence('abracadabra', 'aaa'), true);
assert.strictEqual(checkSubsequence('hello world', 'hlo'), true);
});

it('returns false when order is broken', () => {
assert.strictEqual(checkSubsequence('abcde', 'aec'), false);
assert.strictEqual(checkSubsequence('abcdef', 'z'), false);
});

it('handles empty subsequence', () => {
assert.strictEqual(checkSubsequence('anything', ''), true);
});

it('is case-sensitive', () => {
assert.strictEqual(checkSubsequence('abc', 'A'), false);
assert.strictEqual(checkSubsequence('AbC', 'AC'), true);
});

it('handles spaces as normal characters', () => {
assert.strictEqual(checkSubsequence('a b c', 'abc'), true);
assert.strictEqual(checkSubsequence('a b c', 'a c'), true);
});

it('throws if inputs are not strings', () => {
assert.throws(() => checkSubsequence(123 as any, 'abc'), /Both inputs must be strings/);
assert.throws(() => checkSubsequence('abc', null as any), /Both inputs must be strings/);
});
});