//(c) Vasian Cepa 2005 // Version 2 // Taken from: https://www.codeproject.com/Articles/11016/Numeric-String-Sort-in-C using static System.Char; namespace API.Comparators; public static class StringLogicalComparer { public static int Compare(string s1, string s2) { //get rid of special cases if((s1 == null) && (s2 == null)) return 0; if(s1 == null) return -1; if(s2 == null) return 1; if (string.IsNullOrEmpty(s1) && string.IsNullOrEmpty(s2)) return 0; if (string.IsNullOrEmpty(s1)) return -1; if (string.IsNullOrEmpty(s2)) return -1; //WE style, special case var sp1 = IsLetterOrDigit(s1, 0); var sp2 = IsLetterOrDigit(s2, 0); if(sp1 && !sp2) return 1; if(!sp1 && sp2) return -1; int i1 = 0, i2 = 0; //current index while(true) { var c1 = IsDigit(s1, i1); var c2 = IsDigit(s2, i2); int r; // temp result if(!c1 && !c2) { bool letter1 = IsLetter(s1, i1); bool letter2 = IsLetter(s2, i2); if((letter1 && letter2) || (!letter1 && !letter2)) { if(letter1 && letter2) { r = ToLower(s1[i1]).CompareTo(ToLower(s2[i2])); } else { r = s1[i1].CompareTo(s2[i2]); } if(r != 0) return r; } else if(!letter1 && letter2) return -1; else if(letter1 && !letter2) return 1; } else if(c1 && c2) { r = CompareNum(s1, ref i1, s2, ref i2); if(r != 0) return r; } else if(c1) { return -1; } else if(c2) { return 1; } i1++; i2++; if((i1 >= s1.Length) && (i2 >= s2.Length)) { return 0; } if(i1 >= s1.Length) { return -1; } if(i2 >= s2.Length) { return -1; } } } private static int CompareNum(string s1, ref int i1, string s2, ref int i2) { int nzStart1 = i1, nzStart2 = i2; // nz = non zero int end1 = i1, end2 = i2; ScanNumEnd(s1, i1, ref end1, ref nzStart1); ScanNumEnd(s2, i2, ref end2, ref nzStart2); var start1 = i1; i1 = end1 - 1; var start2 = i2; i2 = end2 - 1; var nzLength1 = end1 - nzStart1; var nzLength2 = end2 - nzStart2; if(nzLength1 < nzLength2) return -1; if(nzLength1 > nzLength2) return 1; for(int j1 = nzStart1,j2 = nzStart2; j1 <= i1; j1++,j2++) { var r = s1[j1].CompareTo(s2[j2]); if(r != 0) return r; } // the nz parts are equal var length1 = end1 - start1; var length2 = end2 - start2; if(length1 == length2) return 0; if(length1 > length2) return -1; return 1; } //lookahead private static void ScanNumEnd(string s, int start, ref int end, ref int nzStart) { nzStart = start; end = start; var countZeros = true; while(IsDigit(s, end)) { if(countZeros && s[end].Equals('0')) { nzStart++; } else countZeros = false; end++; if(end >= s.Length) break; } } }