You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何按指定规则高效比较字母数字混合字符串(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"

核心需求

仅包含数字或仅包含字母的字符串比较逻辑十分简单,但二者混合时逻辑更复杂。核心规则为:将连续的数字组作为一个完整数值进行比较,而非逐字符对比单个数字字符。

现有实现

我目前采用暴力拆分法实现:先把字符串拆分为字母分组和数字分组,再逐组分别比较。该方案可正常运行,但性能不佳、实现不够优雅,希望了解是否有更优的实现方式。以下是可直接在Playground运行的完整依赖扩展与方法代码:

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"))

内容的提问来源于stack exchange,提问作者Aswath

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.01 04:57:54