Skip to content

Instantly share code, notes, and snippets.

@aswathr
Last active June 8, 2022 12:51
Show Gist options
  • Save aswathr/808cb592b4873995d97ac4b5ebab96c0 to your computer and use it in GitHub Desktop.
Save aswathr/808cb592b4873995d97ac4b5ebab96c0 to your computer and use it in GitHub Desktop.
Alphanumeric comparison in swift
// "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