Last active
June 8, 2022 12:51
-
-
Save aswathr/808cb592b4873995d97ac4b5ebab96c0 to your computer and use it in GitHub Desktop.
Alphanumeric comparison in swift
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
// "b" > "a" | |
// "3" > "1" | |
// "ac" > "ab" | |
// "32" > "25" | |
// "abcd1" > "abc2" | |
// "abc123a" > "abc2a" | |
// "abc123a" < "abc1234a" | |
// "abc123" < "abc123a" | |
// "abc12a49" > "abc12a39" | |
// "123ab3" = "123ab3" | |
// "ab12" > "12ab" | |
// "ab12" > "345" | |
extension RangeReplaceableCollection { | |
mutating func removeFirstSafe() -> Element? { | |
guard !isEmpty else { return nil } | |
return removeFirst() | |
} | |
} | |
extension String { | |
func split(grouping charSets: [[Character]]) -> [(CharacterType, String)] { | |
var subStrings = [(CharacterType, String)]() | |
var copy = self | |
copy.__split(grouping: charSets, groupedSubstrings: &subStrings) | |
return subStrings | |
} | |
mutating func __split(grouping charSets: [[Character]], groupedSubstrings: inout [(CharacterType, String)]) { | |
guard let previousCharacter: Character = removeFirstSafe() else { | |
return | |
} | |
var groupedSubString = String(previousCharacter) | |
let prevCharSetGroup: CharacterType = charSets.indexOfCharSetGroupContainingCharacter(previousCharacter) | |
while let currentCharacter = first, charSets.indexOfCharSetGroupContainingCharacter(currentCharacter) == prevCharSetGroup { | |
groupedSubString.append(currentCharacter) | |
removeFirst() | |
} | |
groupedSubstrings.append((prevCharSetGroup, groupedSubString)) | |
__split(grouping: charSets, groupedSubstrings: &groupedSubstrings) | |
} | |
} | |
enum CharacterType: Int, Comparable { | |
case alphabet = 1 | |
case number = 0 | |
case unknown = -1 | |
static func < (lhs: CharacterType, rhs: CharacterType) -> Bool { | |
lhs.rawValue < rhs.rawValue | |
} | |
} | |
extension Array where Element == [Character] { | |
func indexOfCharSetGroupContainingCharacter(_ char: Character) -> CharacterType { | |
for (index, group) in self.enumerated() { | |
if group.contains(char) { return CharacterType(rawValue: index) ?? .unknown } | |
} | |
return .unknown | |
} | |
} | |
extension Collection { | |
subscript (safe index: Index) -> Element? { | |
return indices.contains(index) ? self[index] : nil | |
} | |
} | |
struct AlphanumericString { | |
var string: String | |
} | |
func <(lhs: (CharacterType, String), rhs: (CharacterType, String)) -> Bool { | |
if lhs.0 > rhs.0 { return false } | |
else if lhs.0 < rhs.0 { return true } | |
else { | |
if lhs.0 == .alphabet || lhs.0 == .unknown { return lhs.1 < rhs.1 } | |
else { return (Int(lhs.1) ?? 0) < (Int(rhs.1) ?? 0) } | |
} | |
} | |
extension AlphanumericString: Comparable { | |
static func < (lhs: AlphanumericString, rhs: AlphanumericString) -> Bool { | |
if lhs.string == rhs.string { return false } | |
let lhsGrouped = lhs.string.split(grouping: [Array("12345"), Array("abcde")]) | |
let rhsGrouped = rhs.string.split(grouping: [Array("12345"), Array("abcde")]) | |
for idx in lhsGrouped.indices { | |
let lhsItem = lhsGrouped[idx] | |
guard let rhsItem = rhsGrouped[safe: idx] else { return false } | |
if lhsItem < rhsItem { return true } | |
else if rhsItem < lhsItem { return false } | |
} | |
return true | |
} | |
} | |
print(AlphanumericString(string: "abcd1") < AlphanumericString(string: "abc2")) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment