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
38 changes: 33 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,6 @@ const count = stringzy.analyze.wordCount('Hello world'); // 2
- [isMacAddress](#ismacaddress)- Checks if a given string is a valid MAC address.
- [isPanagram](#ispanagram)- Checks if a given string is a pangram (contains every letter of the English alphabet at least once).


### Analysis

- [wordCount](#wordcount) - Counts the number of words in a string
Expand All @@ -116,7 +115,7 @@ const count = stringzy.analyze.wordCount('Hello world'); // 2
- [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)

- [stringRotation](#stringrotation) - Checks if one string is a rotation of another (case sensitive).
### Formatting

- [capitalize](#capitalize) - Capitalizes the first letter of each word
Expand Down Expand Up @@ -1000,9 +999,6 @@ functionWordCount("Can you see the stars tonight?");

- `count` (number): Total number of function words in the string




#### <a id="patterncount"></a>`patternCount(text, pattern)`

Counts the number of times a substring (pattern) occurs in a string, including overlapping occurrences.
Expand Down Expand Up @@ -1096,6 +1092,38 @@ isSubsequence('a b c', 'abc');
| str | string | required | The main string to check within. |
| sub | string | required | The subsequence string to verify against `str`. |

#### <a id="stringrotation"></a>checkStringRotations(str1, str2)
Checks whether a given string `str2` is a rotation of another string `str1`.
Case-sensitive comparison is performed. Both strings must be of equal length to be considered rotations.
Spaces and all characters are treated literally.

```javascript
isRotation('waterbottle', 'erbottlewat');
// true → rotation at position 3

isRotation('abcde', 'cdeab');
// true → rotation at position 2

isRotation('abc', 'abc');
// true → no rotation, identical strings

isRotation('abc', 'cab');
// true → rotation at position 2

isRotation('abc', 'bac');
// false → not a valid rotation

isRotation('ArB', 'Bar');
// false → case-sensitive mismatch

isRotation('abcd', 'abc');
// false → lengths differ
```

| Parameter | Type | Default | Description |
| --------- | ------ | -------- | --------------------------------------------------- |
| str1 | string | required | The original string. |
| str2 | string | required | The string to verify if it is a rotation of `str1`. |

---

Expand Down
9 changes: 4 additions & 5 deletions src/analyzing/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,9 @@ export { patternCount } from './patternCount';
export { vowelConsonantCount } from './vowelConsonantCount';
export { checkMultiplePatterns } from './checkMultiplePatterns';
export { checkSubsequence } from './checkSubsequence';

export { functionWordCount } from './functionWordCount';
export { contentWordCount } from './contentWordCount';

export { checkStringRotations } from './stringRotation';

import { characterCount } from './characterCount';
import { characterFrequency } from './characterFrequency';
Expand All @@ -23,8 +22,7 @@ import { patternCount } from './patternCount';
import { vowelConsonantCount } from './vowelConsonantCount';
import { checkMultiplePatterns } from './checkMultiplePatterns';
import { checkSubsequence } from './checkSubsequence';


import { checkStringRotations } from './stringRotation';

export const analyzing = {
characterCount,
Expand All @@ -36,5 +34,6 @@ export const analyzing = {
patternCount,
vowelConsonantCount,
checkMultiplePatterns,
checkSubsequence
checkSubsequence,
checkStringRotations
};
42 changes: 42 additions & 0 deletions src/analyzing/stringRotation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/**
* Checks if one string is a rotation of another.
*
* A string `str2` is a rotation of `str1` if it can be obtained by shifting
* the characters of `str1` in a circular fashion.
*
* The check is case-sensitive and supports special characters and numbers.
*
* @param {string} str1 - The original string.
* @param {string} str2 - The string to check if it is a rotation of str1.
* @returns {boolean} True if str2 is a rotation of str1, otherwise false.
* @throws {TypeError} If either input is not a string.
*
* @example
* checkStringRotations("abcd", "cdab"); // true
*
* @example
* checkStringRotations("abc", "acb"); // false
*
* @example
* checkStringRotations("hello", "ohell"); // true
*
* @example
* checkStringRotations("", ""); // true
*
* @example
* checkStringRotations("abc", "ab"); // false
*/
export function checkStringRotations(str1: string, str2: string): boolean {
if (typeof str1 !== 'string' || typeof str2 !== 'string') {
throw new TypeError('Both inputs must be strings');
}

// Edge case: both empty strings
if (str1 === '' && str2 === '') return true;

// If lengths differ, they cannot be rotations
if (str1.length !== str2.length) return false;

// Concatenate str1 with itself and check if str2 is a substring
return (str1 + str1).includes(str2);
}
44 changes: 44 additions & 0 deletions src/tests/analyzing/stringRotation.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { describe, it } from 'node:test';
import assert from 'node:assert';
import { checkStringRotations } from '../../analyzing/stringRotation';

describe('checkStringRotations', () => {
it('returns true for valid rotations', () => {
assert.strictEqual(checkStringRotations('abcd', 'cdab'), true);
assert.strictEqual(checkStringRotations('hello', 'ohell'), true);
assert.strictEqual(checkStringRotations('12345', '45123'), true);
assert.strictEqual(checkStringRotations('!@#$', '#$!@'), true);
});

it('returns false for invalid rotations', () => {
assert.strictEqual(checkStringRotations('abc', 'acb'), false);
assert.strictEqual(checkStringRotations('hello', 'helol'), false);
assert.strictEqual(checkStringRotations('12345', '54321'), false);
});

it('is case-sensitive', () => {
assert.strictEqual(checkStringRotations('ArB', 'Bar'), false);
assert.strictEqual(checkStringRotations('Case', 'case'), false);
assert.strictEqual(checkStringRotations('XYZ', 'yzx'), false);
});

it('returns true for empty strings', () => {
assert.strictEqual(checkStringRotations('', ''), true);
});

it('returns false for strings of different lengths', () => {
assert.strictEqual(checkStringRotations('abc', 'ab'), false);
assert.strictEqual(checkStringRotations('abcd', ''), false);
});

it('handles special characters correctly', () => {
assert.strictEqual(checkStringRotations('a@b$c', 'b$ca@'), true);
assert.strictEqual(checkStringRotations('a@b$c', 'c$a@b'), false);
});

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