/**
* @namespace String
*/
/**
* Calculate edit distance between string a and b
*
* @memberof String
* @see {@link https://en.wikipedia.org/wiki/Edit_distance|Article on Wikipedia}
* @param {string} a A
* @param {string} b B
* @returns {number} Distance
*/
function editDistance(a, b) {
let matrix = [], i, j;
if(a.length === 0) { return b.length; }
if(b.length === 0) { return a.length; }
if(a === b) { return 0; }
// increment along the first column of each row
for(i = 0; i <= b.length; i++) {
matrix[i] = [i];
}
// increment each column in the first row
for(j = 0; j <= a.length; j++){
matrix[0][j] = j;
}
// Fill in the rest of the matrix
for(i = 1; i <= b.length; i++){
for(j = 1; j <= a.length; j++){
if(b.charAt(i-1) === a.charAt(j-1)){
matrix[i][j] = matrix[i-1][j-1];
} else {
matrix[i][j] = Math.min(matrix[i-1][j-1] + 1, // substitution
Math.min(matrix[i][j-1] + 1, // insertion
matrix[i-1][j] + 1)); // deletion
}
}
}
return matrix[b.length][a.length];
}
/**
* Get similarity ratio based on edit distance
*
* @memberof String
* @see {@link String.editDistance}
* @param {string} a A
* @param {string} b B
* @returns {number} Ratio
*/
function getSimilarity(a, b) {
const l = Math.max(a.length, b.length);
return (l - String.editDistance(a, b)) / l;
}
/**
* Checks is given value is String and is empty
*
* @memberof String
* @param {string} sth Something to check
* @returns {boolean} Verdict
*/
function isEmpty (sth) {
return typeof sth === 'string' && sth.length === 0;
}
/**
* Checks is given value is String and is not empty
*
* @memberof String
* @param {string} sth Something to check
* @returns {boolean} Verdict
*/
function isNotEmpty (sth) {
return typeof sth === 'string' && sth.length > 0;
}
/**
* Checks is given value isn't a String, or it is empty
*
* @memberof String
* @param {string} sth Something to check
* @returns {boolean} Verdict
*/
function isInvalidOrEmpty (sth) {
return typeof sth !== 'string' || sth.length === 0;
}
/**
* Returns string with capitalised first letter
*
* @memberof String.prototype
* @param {boolean} [lower=false] Flag if it should lower all letters first
* @returns {string} New string
*/
function capitaliseFirstLetter(lower) {
let value = this.valueOf();
if(lower) {
value = value.toLowerCase();
}
return value.replace(/[a-z]/i, function(m) { return m.toUpperCase(); });
}
/**
* Returns string with lower first letter
*
* @memberof String.prototype
* @returns {string} New string
*/
function lowerFirstLetter() {
return this.valueOf().replace(/[a-z]/i, function(m) { return m.toLowerCase(); });
}
/**
* Returns string with removed cases
*
* @memberof String.prototype
* @returns {string} New string
*/
function noCase() {
let value = this.valueOf();
// detect capitalized snake case
if(/^[A-Z0-9_]+$/.test(value)) {
return value.replace(/_/g, ' ').toLowerCase();
}
// clean kebab and snake case
value = value.replace(/[-_]/g, ' ');
// clean special characters
value = value.replace(/[^a-z0-9 ]/gi, '');
// clean pascal case
value = value.lowerFirstLetter();
// clean camel case
value = value.replace(/([A-Za-z])([0-9])/g, function(m, m1, m2) { return m1 + ' ' + m2; });
value = value.replace(/[A-Z][a-z]/g, function(m) { return ' ' + m.toLowerCase(); });
value = value.replace(/([a-z0-9])([A-Z])/g, function(m, m1, m2) { return m1 + ' ' + m2; });
// minimize white spaces
value = value.trim().replace(/\s{2,}/g, ' ');
return value;
}
/**
* Returns string in camelCase
*
* @memberof String.prototype
* @returns {string} String in camelCase
*/
function toCamelCase() {
let value = this.valueOf();
// normalize
value = value.noCase();
// replace
value = value.replace(/ [a-z0-9]/gi, function(m) { return m[1].toUpperCase(); });
return value;
}
/**
* Returns string in PascalCase
*
* @memberof String.prototype
* @returns {string} String in PascalCase
*/
function toPascalCase() {
return this.toCamelCase().capitaliseFirstLetter(false);
}
/**
* Returns string in kebab-case
*
* @memberof String.prototype
* @returns {string} String in kebab-case
*/
function toKebabCase() {
let value = this.valueOf();
// normalize
value = value.noCase();
// replace
value = value.replace(/\s/g, '-');
return value;
}
/**
* Returns string in snake_case
*
* @memberof String.prototype
* @param {boolean} [convertToUpperCase=false] Set this flag to convert to UpperCase
* @returns {string} String in snake_case
*/
function toSnakeCase(convertToUpperCase) {
const toUpperCase = convertToUpperCase || false;
let value = this.valueOf();
// normalize
value = value.noCase();
// replace
value = value.replace(/\s/g, '_');
if(toUpperCase) return value.toUpperCase();
return value;
}
/**
* Returns checksum crc32
*
* @memberof String.prototype
* @author joelpt
* @author schnaader
* @see {@link https://stackoverflow.com/a/3276730 | Stack Overflow Answer}
* @returns {string} Checksum
*/
function toChecksum() {
let value, i, chk;
value = this.valueOf();
chk = 0x12345678;
for (i = 0; i < value.length; i++) {
chk += value.charCodeAt(i) * (i + 1);
}
return chk;
}
/**
* Returns string in boolean
*
* @memberof String.prototype
* @returns {boolean} True if string looks somehow like 'true'
*/
function toBoolean() {
return this.valueOf().toLowerCase() === 'true';
}
/**
* Returns reversed string
*
* @memberof String.prototype
* @returns {string} Reversed string
*/
function reverse() {
return this.valueOf().split('').reverse().join('');
}
/**
* Check if string is like given query (you can use regexp notation)
*
* @memberof String.prototype
* @param {string} query Query
* @returns {boolean} Verdict
*/
function isLike(query) {
return new RegExp('^' + query + '$').test(this.valueOf());
}
/**
* Polyfill for ECMAScript 2015 for String.prototype.includes
*
* @memberof String.prototype
* @param {string} search Search for
* @param {number} [start=0] Searching start position
* @returns {boolean} Verdict
*/
function includes(search, start) {
const _start = typeof start !== 'number' ? 0 : start;
if (_start + search.length > this.length) {
return false;
}
return this.indexOf(search, _start) !== -1;
}
export default {
static: {
editDistance,
getSimilarity,
isEmpty,
isNotEmpty,
isInvalidOrEmpty
},
method: {
capitaliseFirstLetter,
lowerFirstLetter,
noCase,
toCamelCase,
toPascalCase,
toKebabCase,
toSnakeCase,
toChecksum,
toBoolean,
reverse,
isLike,
includes
}
};