【问题标题】:python sorting negative and/or decimal alphanumeric stringspython对负数和/或十进制字母数字字符串进行排序
【发布时间】:2025-11-29 05:20:02
【问题描述】:

我在对包含负数和/或十进制字母数字字符串的字符串列表进行排序时遇到问题。这是我目前所拥有的:

import re

format_ids = ["synopsys_SS_2v_-40c_SS.lib",
              "synopsys_SS_1v_-40c_SS.lib",
              "synopsys_SS_1.2v_-40c_SS.lib", 
              "synopsys_SS_1.4v_-40c_SS.lib",
              "synopsys_SS_2v_-40c_TT.lib",
              "synopsys_FF_3v_25c_FF.lib",
              "synopsys_TT_4v_125c_TT.lib",
              "synopsys_TT_1v_85c_TT.lib",
              "synopsys_TT_10v_85c_TT.lib",
              "synopsys_FF_3v_-40c_SS.lib",
              "synopsys_FF_3v_-40c_TT.lib"]

selector = r'.*(FF|TT|SS)_([-\.\d]+v)_([-\.\d]+c)_(FF|TT|SS).*'
#key = [2,1,3]
key = 2
produce_groups = False

if isinstance(key, int):
    key = [key]

convert = lambda text: float(text) if text.isdigit() else text
alphanum_key = lambda k: [convert(c) for c in re.split('([-.\d]+)', k)]
split_list = lambda name: tuple(alphanum_key(re.findall(selector,name)[0][i]) for i in key)
format_ids.sort(key=split_list)

print "\n".join(format_ids)

我期待以下输出(按第三键排序):

synopsys_SS_2v_-40c_SS.lib
synopsys_SS_1v_-40c_SS.lib
synopsys_SS_1.2v_-40c_SS.lib
synopsys_SS_1.4v_-40c_SS.lib
synopsys_SS_2v_-40c_TT.lib
synopsys_FF_3v_-40c_SS.lib
synopsys_FF_3v_-40c_TT.lib
synopsys_FF_3v_25c_FF.lib
synopsys_TT_1v_85c_TT.lib
synopsys_TT_10v_85c_TT.lib
synopsys_TT_4v_125c_TT.lib

但我得到以下信息(所有负数都列在最后):

synopsys_FF_3v_25c_FF.lib
synopsys_TT_1v_85c_TT.lib
synopsys_TT_10v_85c_TT.lib
synopsys_TT_4v_125c_TT.lib
synopsys_SS_2v_-40c_SS.lib
synopsys_SS_1v_-40c_SS.lib
synopsys_SS_1.2v_-40c_SS.lib
synopsys_SS_1.4v_-40c_SS.lib
synopsys_SS_2v_-40c_TT.lib
synopsys_FF_3v_-40c_SS.lib
synopsys_FF_3v_-40c_TT.lib

现在,对于第二个键的小数(将键变量更改为 1 (key=1)),我得到:

synopsys_SS_1v_-40c_SS.lib
synopsys_TT_1v_85c_TT.lib
synopsys_SS_2v_-40c_SS.lib
synopsys_SS_2v_-40c_TT.lib
synopsys_FF_3v_25c_FF.lib
synopsys_FF_3v_-40c_SS.lib
synopsys_FF_3v_-40c_TT.lib
synopsys_TT_4v_125c_TT.lib
synopsys_TT_10v_85c_TT.lib
synopsys_SS_1.2v_-40c_SS.lib
synopsys_SS_1.4v_-40c_SS.lib

期待:

synopsys_SS_1v_-40c_SS.lib
synopsys_TT_1v_85c_TT.lib
synopsys_SS_1.2v_-40c_SS.lib
synopsys_SS_1.4v_-40c_SS.lib
synopsys_SS_2v_-40c_SS.lib
synopsys_SS_2v_-40c_TT.lib
synopsys_FF_3v_25c_FF.lib
synopsys_FF_3v_-40c_SS.lib
synopsys_FF_3v_-40c_TT.lib
synopsys_TT_4v_125c_TT.lib
synopsys_TT_10v_85c_TT.lib

非常感谢任何建议。

编辑:我最终使用了@StephenRauch 描述的simpler method

import re
def sort_names(format_ids, selector, key=1):

    if isinstance(key, int):
        key = [key]

    SELECTOR_RE = re.compile(selector)

    def convert(x):
        try:
            return float(x[:-1])
        except ValueError:
            return x

    def sort_keys(key):
        def split_fid(x):
            x = SELECTOR_RE.split(x)
            return tuple([convert(x[i]) for i in key])
        return split_fid

    format_ids.sort(key=sort_keys(key))

format_ids = ["synopsys_SS_2v_-40c_SS.lib",
              "synopsys_SS_1v_-40c_SS.lib",
              "synopsys_SS_1.2v_-40c_SS.lib",
              "synopsys_SS_1.4v_-40c_SS.lib",
              "synopsys_SS_2v_-40c_TT.lib",
              "synopsys_FF_3v_25c_FF.lib",
              "synopsys_TT_4v_125c_TT.lib",
              "synopsys_TT_1v_85c_TT.lib",
              "synopsys_TT_10v_85c_TT.lib",
              "synopsys_FF_3v_-40c_SS.lib",
              "synopsys_FF_3v_-40c_TT.lib"]

selector = r'.*(FF|TT|SS)_([-\.\d]+v)_([-\.\d]+c)_(FF|TT|SS).*'
key = [2,1,3]

sort_names(format_ids,selector,key)

【问题讨论】:

    标签: python sorting numbers decimal alphanumeric


    【解决方案1】:

    需要稍微不同地测试数字,并且 re.split() 被赋予前导 '',它正在抛出转换例程。

    固定代码:

    key = [2,1,3]
    
    def convert(x):
        try:
            return float(x)
        except ValueError:
            return x
    
    alphanum_keys = lambda k: (convert(c) for c in re.split('([-.\d]+)', k))
    alphanum_key = lambda k: [i for i in alphanum_keys(k) if i != ''][0]
    split_list = lambda name: [
        alphanum_key(re.findall(selector, name)[0][i]) for i in key]
    format_ids.sort(key=split_list)
    

    替代(更简单)解决方案:

    但是...所有这些 lambdas 和 regexs 都比解决这个问题所需的复杂得多。怎么样:

    def sort_key(keys):
    
        def convert(x):
            try:
                return float(x[:-1])
            except ValueError:
                return x
    
        def f(x):
            x = x.split('_')
            return tuple([convert(x[i]) for i in keys])
        return f
    
    format_ids.sort(key=sort_key([3, 2, 4]))
    

    如何?

    sort_keys() 返回一个函数f()。这是传递给sort() 以评估排序顺序的一个参数的函数。函数f() 将使用传递给sort_keys() 的键值,因为这些值是available at the time f() is defined。这称为closure

    结果:

    synopsys_SS_1v_-40c_SS.lib
    synopsys_SS_1.2v_-40c_SS.lib
    synopsys_SS_1.4v_-40c_SS.lib
    synopsys_SS_2v_-40c_SS.lib
    synopsys_SS_2v_-40c_TT.lib
    synopsys_FF_3v_-40c_SS.lib
    synopsys_FF_3v_-40c_TT.lib
    synopsys_FF_3v_25c_FF.lib
    synopsys_TT_1v_85c_TT.lib
    synopsys_TT_10v_85c_TT.lib
    synopsys_TT_4v_125c_TT.lib
    

    【讨论】:

    • @Steven\ Rauch,感谢您提供替代解决方案,我试图实现它,但它对我不起作用。就我而言,我必须按用户定义的正则表达式进行拆分,因此我将 x.split('_') 替换为 x.split(selector)。考虑到这一切,f(x) 是在哪里调用的?
    • @Kidneys,我添加了对闭包的解释。如果这不能回答 它在哪里被调用? 也请务必通过 selectorsort_keys,如果它将用于f()
    • @Steven\ Rauch,我完全错过了那个,感谢您的澄清。我刚刚更新了上面的代码并得到了“列表索引超出范围错误”。我哪里错了?
    • @Kidneys,您没有进行正则表达式拆分,您仍在进行简单的字符串拆分。
    • @StevenRauch,刚刚对您的编辑做了一个小改动,现在一切都很好,谢谢!!
    【解决方案2】:

    您的问题的很大一部分是只有实际数字被认为是数字,而不是破折号和句点,因此在您的代码中,“-40”.isdigit() 或“1.4”.isdigit() 之类的内容将是 False,并且保持为文本而不是转换为浮点数。

    【讨论】: