通过对字符串中的外观进行排序来对 str 和 int 的值进行排序

Sort values for both str and int by ranking appearance in a string

我必须对字符串中的关键字和值进行排序。

这是我的尝试:

import re
phrase='00 is the price of the car, it is 10 years old. And this sandwish cost me 10.34£'
list1 = (re.findall('\d*\.?\d+', phrase)) #this is to make a list that find all the ints in my phrase and sort them (1000, 10, 10.34)

list2= ['car', 'year', 'sandwish'] #this is to make a list of all the keywords in the phrase I need to find.

joinedlist = list1 + list2 #This is the combination of the 2 lists int and str that are in my sentence (the key elements)

filter1 = (sorted(joinedlist, key=phrase.find)) #This is to find all the key elements in my phrase and sort them by order of appearance.

print(filter1)

不幸的是,在某些情况下,因为“sorted”函数是按词法排序工作的,所以积分会以错误的顺序打印。这意味着在某些情况下,例如这种情况,输出将是:

['1000', '10', 'car', 'year', 'sandwich', '10.34']

而不是:

['1000', 'car', '10', 'year', 'sandwich', '10.34']

因为汽车出现在初始短语中的 10 之前。

词法排序与它无关,因为你的排序key是在原词组中的位置;所有排序都是按数值(find 返回的索引)完成的。 '10' 出现“乱序”的原因是 phrase.find returns 它第一次出现,它在字符串的 1000 部分内!

与其将句子分成两个列表,然后尝试用 sort 重新组合它们,为什么不只使用一个正则表达式来选择您想要保留的不同种类的东西呢?这样你就根本不需要re-sort它们了:

>>> re.findall('\d*\.?\d+|car|year|sandwish', phrase)
['1000', 'car', '10', 'year', 'sandwish', '10.34']

问题是 101000 每个都具有与 Python 的默认字符串查找相同的值。两者都位于字符串的开头,因为 101000.

的子字符串

可以 phrase 执行正则表达式查找,以通过使用 \b 字边界来执行您尝试的方法,以便 10仅匹配字符串中的 10

def finder(s):
    if m:=re.search(rf'\b{s}\b', phrase):
        return m.span()[0]
    elif m:=re.search(rf'\b{s}', phrase):
        return m.span()[0]
    return -1   

测试一下:

>>> sorted(joinedlist, key=finder)
['1000', 'car', '10', 'year', 'sandwish', '10.34']

但是,如果您将 phrase 变成关键字的查找列表,会更容易。您需要将 year 作为关键字与 phrase 中的 years 进行一些处理;您可以只使用正则表达式 r'\d+\.\d+|\w+' 作为正则表达式来查找单词,然后 str.startswith() 来测试它是否足够接近:

pl=re.findall(r'\d+\.\d+|\w+', phrase)

def finder2(s):
    try:                    # first try an exact match
        return pl.index(s)
    except ValueError:
        pass                # not found; now try .startswith()
    try:    
        return next(i for i,w in enumerate(pl) if w.startswith(s))  
    except StopIteration:
        return -1   

>>> sorted(joinedlist, key=finder2)
['1000', 'car', '10', 'year', 'sandwish', '10.34']