Last active
June 22, 2017 06:44
-
-
Save detomon/a90bda714e3a3b651c6f to your computer and use it in GitHub Desktop.
Compare strings using natural ordering by interpreting continuous digits as integers
This file contains hidden or 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
#include <stdio.h> | |
#include <stdlib.h> | |
#include <Block.h> | |
/** | |
* Compare strings using natural ordering | |
* | |
* Interprets continuous digits as integers, e.g, the string "year 2015" will be | |
* greater than "year 308", although "3" has a higher character value than "2". | |
* [Trailing and pending whitespace is ignored.] Whitespace between tokens is | |
* interpreted as single space. | |
* | |
* Returns an integer greater than, equal to, or less than 0, according as the | |
* string `s1` is greater than, equal to, or less than the string `s2`. | |
*/ | |
int strnatcmp(char const* s1, char const* s2) | |
{ | |
#define ISSPACE(c) (c == ' ' || c == '\t' || c == '\n' || c == '\r') | |
#define ISDIGIT(c) (c >= '0' && c <= '9') | |
int c1, c2; | |
// ignore leading whitespace | |
//while (ISSPACE(*s1)) s1++; | |
//while (ISSPACE(*s2)) s2++; | |
while (*s1 && *s2) { | |
c1 = *s1++; | |
c2 = *s2++; | |
// read integer value and negate | |
// to distinguish from normal character | |
if (ISDIGIT(c1)) { | |
c1 -= '0'; | |
while (ISDIGIT(*s1)) { | |
c1 = c1 * 10 + (*s1 - '0'); | |
s1++; | |
} | |
c1 = -c1; | |
} | |
// interpret whitespace as single space | |
else if (ISSPACE(c1)) { | |
while (ISSPACE(*s1)) s1++; | |
c1 = ' '; | |
} | |
// read integer value and negate | |
// to distinguish from normal character | |
if (ISDIGIT(c2)) { | |
c2 -= '0'; | |
while (ISDIGIT(*s2)) { | |
c2 = c2 * 10 + (*s2 - '0'); | |
s2++; | |
} | |
c2 = -c2; | |
} | |
// interpret whitespace as single space | |
else if (ISSPACE(c2)) { | |
while (ISSPACE(*s2)) s2++; | |
c2 = ' '; | |
} | |
// tokens (integer or character) are not equal | |
if (c1 != c2) { | |
// negate when both tokens are integers | |
// to return correct value | |
if (c1 < 0 && c2 < 0) { | |
c1 = -c1; | |
c2 = -c2; | |
} | |
return c1 - c2; | |
} | |
} | |
// ignore pending whitespace | |
//while (ISSPACE(*s1)) s1++; | |
//while (ISSPACE(*s2)) s2++; | |
return *s1 - *s2; | |
} | |
int main (void) | |
{ | |
char const* strings [] = { | |
"v4.0.6", | |
"v3.2", | |
"v3.7", | |
"v4.0.5", | |
"v4.0", | |
"v4.0.2", | |
"v3.1.9", | |
"v3.3.3", | |
"v3.5", | |
"v3.2.1", | |
"v3.3.2", | |
"v4.0.7", | |
"v4.0.1", | |
"v3.1.10", | |
"v3.8", | |
"v3.5.1", | |
"v3.4", | |
"v4.0.4", | |
"v3.3", | |
"v3.9", | |
"v3.1.11", | |
"v3.6", | |
"v3.3.4", | |
"v4.0.3", | |
"v3.3.1", | |
}; | |
int count = sizeof(strings) / sizeof(strings[0]); | |
qsort_b(strings, count, sizeof(char const*), (int(^)(void const*, void const*)) ^(char const** a, char const** b) { | |
return strnatcmp(*a, *b); | |
}); | |
for (int i = 0; i < count; i++) { | |
printf("%s\n", strings[i]); | |
} | |
return 0; | |
} |
This file contains hidden or 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
function strnatcmp(s1, s2) { | |
function isspace(c) { | |
return c <= 0x20 || c == 0xA0; | |
} | |
function isdigit(c) { | |
return c >= 0x30 && c <= 0x39; | |
} | |
var c1, c2; | |
var i1 = 0, i2 = 0; | |
// ignore leading whitespace | |
while (isspace(s1[i2])) i1++; | |
while (isspace(s2[i1])) i2++; | |
while (i1 < s1.length && i2 < s2.length) { | |
c1 = s1.charCodeAt(i1++); | |
c2 = s2.charCodeAt(i2++); | |
// read integer value and negate | |
// to distinguish from normal character | |
if (isdigit (c1)) { | |
c1 -= '0'; | |
while (isdigit(s1.charCodeAt(i1))) { | |
c1 = c1 * 10 + (s1.charCodeAt(i1) - '0'); | |
i1++; | |
} | |
c1 = -c1; | |
} | |
// interpret whitespace as single space | |
else if (isspace(c1)) { | |
while (isspace(s1.charCodeAt(i1))) i1++; | |
c1 = ' '; | |
} | |
// read integer value and negate | |
// to distinguish from normal character | |
if (isdigit (c2)) { | |
c2 -= '0'; | |
while (isdigit (s2.charCodeAt(i2))) { | |
c2 = c2 * 10 + (s2.charCodeAt(i2) - '0'); | |
i2++; | |
} | |
c2 = -c2; | |
} | |
// interpret whitespace as single space | |
else if (isspace(c2)) { | |
while (isspace(s2.charCodeAt(i2))) i2++; | |
c2 = ' '; | |
} | |
// tokens (integer or character) are not equal | |
if (c1 != c2) { | |
// negate when both tokens are integers | |
// to return correct value | |
if (c1 < 0 && c2 < 0) { | |
c1 = -c1; | |
c2 = -c2; | |
} | |
return c1 - c2; | |
} | |
} | |
// ignore pending whitespace | |
while (isspace(s1.charCodeAt(i1))) i1++; | |
while (isspace(s2.charCodeAt(i2))) i2++; | |
return s1.charCodeAt(i1) - s2.charCodeAt(i2); | |
} | |
var strings = [ | |
"v3.1.10", | |
"v3.1.11", | |
"v3.1.9", | |
"v3.2", | |
"v3.2.1", | |
"v3.3", | |
"v3.3.1", | |
"v3.3.2", | |
"v3.3.3", | |
"v3.3.4", | |
"v3.4", | |
"v3.5", | |
"v3.5.1", | |
"v3.6", | |
"v3.7", | |
"v3.8", | |
"v3.9", | |
"v4.0", | |
"v4.0.1", | |
"v4.0.2", | |
"v4.0.3", | |
"v4.0.4", | |
"v4.0.5", | |
"v4.0.6", | |
"v4.0.7", | |
]; | |
strings.sort(strnatcmp); | |
console.log(strings); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment