Skip to content

Commit

Permalink
feat: add the deconstruct function to the class
Browse files Browse the repository at this point in the history
This new function allows users to deconstruct strings of letters and numbers and decode them into an
array of integers For example:
`'C3ABC123EFGH456` deconstructs to `[3, 3, 731, 123, 92126, 456]`

Resolves: #37
  • Loading branch information
M-Scott-Lassiter committed May 3, 2022
1 parent 3bc1e2a commit 5df23ec
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 21 deletions.
75 changes: 54 additions & 21 deletions API.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,20 @@
- [decode][15]
- [Parameters][16]
- [Examples][17]
- [deconstruct][18]
- [Parameters][19]
- [Examples][20]

## AlphanumericEncoder

A class for encoding and decoding base 10 integers to a custom alphanumeric base representation.

### Parameters

- `configOptions` **[object][18]?** Optional object defining initial settings for the class (optional, default `{}`)
- `configOptions` **[object][21]?** Optional object defining initial settings for the class (optional, default `{}`)

- `configOptions.allowLowerCaseDictionary` **[boolean][19]?** Whether or not to allow lower case letters in the dictionary
- `configOptions.dictionary` **[string][20]?** Starting dictionary to use
- `configOptions.allowLowerCaseDictionary` **[boolean][22]?** Whether or not to allow lower case letters in the dictionary
- `configOptions.dictionary` **[string][23]?** Starting dictionary to use

### Examples

Expand Down Expand Up @@ -61,7 +64,7 @@ Returns or sets the current dictionary.

#### Parameters

- `newDictionary` **[string][20]** (If setting) String of unique letters and numbers, in order, for the new dictionary
- `newDictionary` **[string][23]** (If setting) String of unique letters and numbers, in order, for the new dictionary

#### Examples

Expand All @@ -76,19 +79,19 @@ console.log(encoder.dictionary) // 'ABCD'
encoder.dictionary = 'ABCDA' // Throws error because the letter 'A' is repeated
```

- Throws **[RangeError][21]** if setting dictionary to `null`, `undefined` or empty string (i.e. `''`)
- Throws **[RangeError][21]** if `newDictionary` contains a non-alphanumeric character
- Throws **[RangeError][21]** if `newDictionary` has a repeating character
- Throws **[RangeError][24]** if setting dictionary to `null`, `undefined` or empty string (i.e. `''`)
- Throws **[RangeError][24]** if `newDictionary` contains a non-alphanumeric character
- Throws **[RangeError][24]** if `newDictionary` has a repeating character

Returns **[string][20]** (If used as getter) The current dictionary in use
Returns **[string][23]** (If used as getter) The current dictionary in use

### allowLowerCaseDictionary

Returns or sets a boolean value that determines whether the dictionary will allow lower case letters or not.

#### Parameters

- `isAllowed` **[boolean][19]** (If setting). Accept truthy or falsy statements.
- `isAllowed` **[boolean][22]** (If setting). Accept truthy or falsy statements.

#### Examples

Expand All @@ -105,7 +108,7 @@ encoder.dictionary = 'ABCDefg'
console.log(encoder.dictionary) // 'ABCDefg'
```

Returns **[boolean][19]** (If used as getter)
Returns **[boolean][22]** (If used as getter)

### resetDefaultDictionary

Expand All @@ -130,7 +133,7 @@ Takes any number and converts it into a base (dictionary length) letter combo.

#### Parameters

- `integerToEncode` **[number][22]** Base 10 integer. If passed a non-integer number, decimal values are truncated.
- `integerToEncode` **[number][25]** Base 10 integer. If passed a non-integer number, decimal values are truncated.
Passing zero, negative numbers, or non-numbers will return `undefined`.

#### Examples
Expand Down Expand Up @@ -169,17 +172,17 @@ console.log(encoder.encode(null)) // undefined
console.log(encoder.encode(undefined)) // undefined
```

- Throws **[RangeError][21]** if `integerToEncode` exceeds the maximum safe integer for Javascript (`2^53 - 1 = 9007199254740991`).
- Throws **[RangeError][24]** if `integerToEncode` exceeds the maximum safe integer for Javascript (`2^53 - 1 = 9007199254740991`).

Returns **[string][20]** Dictionary encoded value
Returns **[string][23]** Dictionary encoded value

### decode

Takes any string and converts it into a base 10 integer based on the defined dictionary.

#### Parameters

- `stringToDecode` **[string][20]** If passed a non-integer number, decimal values are truncated.
- `stringToDecode` **[string][23]** If passed a non-integer number, decimal values are truncated.
Passing an empty string, `null`, or `undefined` will return `undefined`.

#### Examples
Expand Down Expand Up @@ -207,9 +210,34 @@ console.log(encoder.decode('ADBAC')) // 551
console.log(encoder.decode('ANE')) // undefined
```

- Throws **[RangeError][21]** if the decoded integer exceeds the maximum safe integer for Javascript (`2^53 - 1 = 9007199254740991`).
- Throws **[RangeError][24]** if the decoded integer exceeds the maximum safe integer for Javascript (`2^53 - 1 = 9007199254740991`).

Returns **[number][22]** Positive integer representation. If one of the characters is not present in the dictionary, it will return `undefined`.
Returns **[number][25]** Positive integer representation. If one of the characters is not present in the dictionary, it will return `undefined`.

### deconstruct

Takes any string of letters and numbers and deconstructs it into an array of base 10 integers based on the defined dictionary.

#### Parameters

- `stringToDeconstruct` **([string][23] | [number][25])** A string of letters and numbers (e.g. `'A7'`, `'AC22'`, `'7C10F'`)

#### Examples

```javascript
const encoder = new AlphanumericEncoder()
console.log(encoder.deconstruct('A')) // [1]
console.log(encoder.deconstruct('AC22')) // [29, 22]
console.log(encoder.deconstruct('C3ABC123EFGH456')) // [3, 3, 731, 123, 92126, 456]
console.log(encoder.deconstruct('A1aB2B')) // [1, 1, undefined, 2, 2]
console.log(encoder.deconstruct('7AC!23A1%')) // [7, undefined, 23, 1, 1, undefined]
console.log(encoder.deconstruct('')) // undefined
```

- Throws **[Error][26]** if the dictionary contains a number as this function would be unable to differentiate between where a number and dictionary value.

Returns **[Array][27]<[number][25]>** An array of numbers. Characters not present in the dictionary are treated as letters and return `undefined` for that array value.
Passing an empty string (`''`), `null`, or `undefined` will return `undefined` for the whole function.

[1]: #alphanumericencoder
[2]: #parameters
Expand All @@ -228,8 +256,13 @@ Returns **[number][22]** Positive integer representation. If one of the characte
[15]: #decode
[16]: #parameters-4
[17]: #examples-5
[18]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object
[19]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean
[20]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String
[21]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/RangeError
[22]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number
[18]: #deconstruct
[19]: #parameters-5
[20]: #examples-6
[21]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object
[22]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean
[23]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String
[24]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/RangeError
[25]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number
[26]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Error
[27]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array
70 changes: 70 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,76 @@ class AlphanumericEncoder {

return result
}

/**
* Takes any string of letters and numbers and deconstructs it into an array of base 10 integers based on the defined dictionary.
*
* @param {string|number} stringToDeconstruct A string of letters and numbers (e.g. `'A7'`, `'AC22'`, `'7C10F'`)
* @throws {Error} if the dictionary contains a number as this function would be unable to differentiate between where a number and dictionary value.
* @returns {number[]} An array of numbers. Characters not present in the dictionary are treated as letters and return `undefined` for that array value.
* Passing an empty string (`''`), `null`, or `undefined` will return `undefined` for the whole function.
* @example
* const encoder = new AlphanumericEncoder()
* console.log(encoder.deconstruct('A')) // [1]
* console.log(encoder.deconstruct('AC22')) // [29, 22]
* console.log(encoder.deconstruct('C3ABC123EFGH456')) // [3, 3, 731, 123, 92126, 456]
* console.log(encoder.deconstruct('A1aB2B')) // [1, 1, undefined, 2, 2]
* console.log(encoder.deconstruct('7AC!23A1%')) // [7, undefined, 23, 1, 1, undefined]
* console.log(encoder.deconstruct('')) // undefined
*
*/
deconstruct(stringToDeconstruct) {
// The dictionary cannot contain numbers, or else the deconstruct function cannot distinguish where
// one code begins and another ends.
if (this.dictionary.match(/[0-9]/)) {
throw new Error('Cannot deconstruct if the dictionary contains numbers.')
}

// Passing falsy values should return undefined
if (
stringToDeconstruct === null ||
stringToDeconstruct === undefined ||
String(stringToDeconstruct).length === 0
) {
return undefined
}

const safeString = String(stringToDeconstruct) // Force argument to string to process number arguments and prevent slice from throwing an error
const deconstructedArray = []
let character = ''
let componentPart = safeString.slice(0, 1) // Initialize with the first character (which has been guranteed present by above guard functions)

// A helper function to push the final component into the array that gets returned. Numbers get added as is, strings get decoded.
const addDecodedElement = (componentString) => {
if (componentString.match(/[0-9]/)) {
deconstructedArray.push(Number.parseInt(componentString, 10)) // Numbers
} else {
deconstructedArray.push(this.decode(componentString)) // Letters
}
}

// If more than one character in safeString, loop through each subsequent character. Once the next character is not
// the same type as the previous group (i.e. flips from letter to number, or vice versa), add the character group to
// deconstructedArray, reset, and move to the next.
for (let i = 2; i <= safeString.length; i++) {
character = safeString.slice(i - 1, i)

// Parse using a RegExp looking for numbers. The !! converts this to either true/false.
if (!!character.match(/[0-9]/) === !!componentPart.match(/[0-9]/)) {
// Same type, concatenate and keep going
componentPart += character
} else {
// Flipped types, add to array and reset
addDecodedElement(componentPart)
componentPart = character
}
}

// Add the final component part (for single character stringToDeconstruct, this will be the only part)
addDecodedElement(componentPart)

return deconstructedArray
}
}

module.exports = AlphanumericEncoder

0 comments on commit 5df23ec

Please sign in to comment.