我试图将用户输入与列表中的一个元素相匹配。
目标是允许用户不键入元素的全名,因为有超过30个字符的元素:
例:用户输入foobar与匹配
- `foobarxx`但不是
- `fobar`允许输入关键字之间的
例:用户输入abc与:匹配
- `abc`, `a bc`, `axxbxxxc`例:apple pie匹配:
- `apple tasty pie party`, `app legit piece`, `aXpXpXlXeX XpXiXe`然而,我只想要最相关的结果,那就是apple tasty pie party
码
我以某种方式取得了以下成绩(1)和(2):
enter = input("input: ")
all_element = ["orange", "apple pie", "pine apple pie", "ppap", "pen pineapple apple pen"]
pattern = ('(?:.+)?'.join(list(enter))).replace(" ", r"\s")
print(pattern)
results = {}
for full_name in all_element:
all = re.findall(pattern, full_name)
if all:
results[len(max(all))] = full_name
print(results)
print(f"result: {results[max(results)]}\n")结果:
input: pen apple
p(?:.+)?e(?:.+)?n(?:.+)?\s(?:.+)?a(?:.+)?p(?:.+)?p(?:.+)?l(?:.+)?e
{22: 'pen pineapple apple pen'}
result: pen pineapple apple pen
input: ora
o(?:.+)?r(?:.+)?a
{3: 'orange'}
result: orange我目前正试图解决(3)
根据(3)中的例子,我的计划是看看有多少次中断,我知道:- "apple pie party“破裂了1次,单词”好吃“- "app legit pieece”破裂了2次,一次间隔,一次"git“--”applegitpieece“破裂次数为n(X)次。
选择故障次数最少的结果,即apple tasty pie party。
从上面的代码中,我只是使用匹配元素的长度来选择结果,这是不准确的,因为ppap导致的是pen pineapple apple pen而不是ppap本身:
input: ppap
p(?:.+)?p(?:.+)?a(?:.+)?p
{4: 'ppap', 21: 'pen pineapple apple pen'}
result: pen pineapple apple pen因此,我想知道如何获得基于(?:.+)?的中断次数,在
result应该是:
{0: 'ppap', 2: 'pen pineapple apple pen'}键是中断次数,项作为选定的元素
这样,我就可以简单地使用min()获得最相关的结果。
问题是,我需要如何编写自己的函数,还是需要使用regex模式来处理这个问题?
发布于 2022-09-03 10:32:06
您可以使用来自Counter模块的collections类来快速消除与前两个条件不匹配的元素。然后,您可以使用SequenceMatcher从difflib中选择其他元素中最相关的选项。
import difflib
from collections import Counter
enter = input("input: ")
all_elements = ["orange", "apple pie", "pine apple pie", "ppap", "pen pineapple apple pen"]
cnts = Counter(enter)
for k,v in cnts.items():
start = len(all_elements) - 1
while start >= 0:
if k not in all_elements[start] or all_elements[start].count(k) < v:
del all_elements[start]
start -= 1
results = {}
for elem in all_elements:
matcher = difflib.SequenceMatcher(a=enter, b=elem)
num = matcher.quick_ratio()
blocks = len(matcher.get_matching_blocks())
results[elem] = (num, blocks)
min_blocks = min([i[1] for i in results.values()])
min_elems = {k:v[0] for k,v in results.items() if v[1] == min_blocks}
print(max(min_elems, key=lambda x: min_elems[x]))发布于 2022-09-03 16:25:13
另一种比较类似字符串的方法是使用Levenshtein模块。
from Levenshtein import distance as lev
st = "apple pie"
l = ['apple tasty pie party', 'app legit piece', 'aXpXpXlXeX XpXiXe']
def find_best_match(some_list, st):
return max((lev(st,s), s) for s in some_list)[1]
find_best_match(l, st)
apple tasty pie partyhttps://stackoverflow.com/questions/73591081
复制相似问题