@technobuddha/library
Version:
A large library of useful functions
71 lines (60 loc) • 2.23 kB
text/typescript
import isNil from 'lodash/isNil';
import compareNumbers from '../compareNumbers';
type Options = {
/** if true, strings are to be compared case insensitive */
caseInsensitive?: boolean;
/** if true, compare numeric portions of the string as numbers */
natural?: boolean;
/** if true, compare strings as version numbers */
version?: boolean;
};
/**
* Compare two strings
*
* @param a First string
* @param b Second string
* @param caseInsensitive True if strings are to be compared case insensitive (default false)
* @returns 0 if a == b; -1 if a < b; 1 if a > b
*
* @default caseInsensitive false
* @default natural false
* @default version false
*/
export function compareStrings(
text1: string | null,
text2: string | null,
{ caseInsensitive = false, natural = false, version = false }: Options = {}
): (-1 | 0 | 1) {
if(text1 === text2) return 0;
if(isNil(text1)) return -1;
if(isNil(text2)) return 1;
if(caseInsensitive) {
text1 = text1.toLowerCase();
text2 = text2.toLowerCase();
if(text1 === text2) return 0;
}
if(version) {
const v1 = text1.trim().split(/[.-]/u);
const v2 = text2.trim().split(/[.-]/u);
const count = Math.max(v1.length, v2.length);
let order = 0 as (-1 | 0 | 1);
for(let i = 0; order === 0 && i < count; ++i)
order = compareStrings(v1[i], v2[i], { natural: true });
return order || compareNumbers(v1.length, v2.length);
} else if(natural) {
const t1 = text1.match(/(\.\d+|\d+|\D+)/ug) ?? [];
const t2 = text2.match(/(\.\d+|\d+|\D+)/ug) ?? [];
const count = Math.min(t1.length, t2.length);
let order = 0 as (-1 | 0 | 1);
for(let i = 0; order === 0 && i < count; ++i) {
if(t1[i] !== t2[i]) {
const n1 = Number.parseFloat(t1[i]);
const n2 = Number.parseFloat(t2[i]);
order = Number.isNaN(n1) || Number.isNaN(n2) ? compareStrings(t1[i], t2[i]) : compareNumbers(n1, n2);
}
}
return order || compareNumbers(t1.length, t2.length);
}
return text1 < text2 ? -1 : 1;
}
export default compareStrings;