Created
May 13, 2016 20:02
-
-
Save icfantv/775a6000748384e9f77569017d67c240 to your computer and use it in GitHub Desktop.
Alpha-Numeric comparator in TypeScript
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export class StringUtils { | |
// shamelessly ripped from http://www.davekoelle.com/alphanum.html | |
/** | |
* Returns whether or not the specified value is a string. | |
* @param value the value to check for a string type. | |
* @returns {boolean} whether or not the specified value is a string. | |
*/ | |
public static isString(value: any): boolean { | |
return typeof value === 'string'; | |
} | |
/** | |
* Returns a number that indicates the order relationship between the two specified strings. | |
* @param s1 {string} the first string | |
* @param s2 the second string | |
* @param caseInsensitive {boolean} whether or not the strings should be compared in a | |
* case-insensitive manner. <em>Default: <code>true</code></em> | |
* @returns {number} a negative number of the first string should appear before the second, | |
* zero (0) if the first string and second string are equivalent, and a positive number if | |
* the first string should appear after the second. | |
*/ | |
public static compare(s1: string, s2: string, caseInsensitive = true): number { | |
if (!StringUtils.isString(s1) || !StringUtils.isString(s2)) { | |
return 0; | |
} | |
if (caseInsensitive) { | |
s1 = s1.toLowerCase(); | |
s2 = s2.toLowerCase(); | |
} | |
let thisMarker = 0; | |
let thatMarker = 0; | |
let s1Length: number = s1.length; | |
let s2Length: number = s2.length; | |
while (thisMarker < s1Length && thatMarker < s2Length) { | |
let thisChunk: string = StringUtils.getChunk(s1, s1Length, thisMarker); | |
thisMarker += thisChunk.length; | |
let thatChunk: string = StringUtils.getChunk(s2, s2Length, thatMarker); | |
thatMarker += thatChunk.length; | |
// if both chunks contain numeric characters, sort them numerically | |
let result = 0; | |
if (StringUtils.isDigit(thisChunk[0]) && StringUtils.isDigit(thatChunk[0])) { | |
// simple chunk comparison by length | |
let thisChunkLength = thisChunk.length; | |
result = thisChunkLength - thatChunk.length; | |
// if equal, the first different number counts | |
if (result === 0) { | |
for (let i = 0; i < thisChunkLength; i++) { | |
result = thisChunk.charCodeAt(i) - thatChunk.charCodeAt(i); | |
if (result !== 0) { | |
return result; | |
} | |
} | |
} | |
} | |
else { | |
result = thisChunk.localeCompare(thatChunk); | |
} | |
if (result !== 0) { | |
return result; | |
} | |
} | |
return s1Length - s1Length; | |
} | |
private static isDigit(ch: string): boolean { | |
return ch.charCodeAt(0) >= 48 && ch.charCodeAt(0) <= 57; | |
} | |
// length of string is passed in for improved efficiency (only need to calculate it once) | |
private static getChunk(s: string, slength: number, marker: number): string { | |
const chunk: Array<string> = []; | |
let c = s[marker]; | |
chunk.push(c); | |
marker++; | |
if (StringUtils.isDigit(c)) { | |
while (marker < slength) { | |
c = s[marker]; | |
if (!StringUtils.isDigit(c)) { | |
break; | |
} | |
chunk.push(c); | |
marker++; | |
} | |
} | |
return chunk.join(''); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment