我正在嘗試將用戶輸入與串列中的元素相匹配。
目標是允許用戶不輸入元素的全名,因為元素長度超過 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
派對”中斷 1 次,由單詞“美味”-“ app
le
git pie
ece”中斷 2 次,一個空格和一個“git” - a
X p
X p
X l
X e
X
X p
X i
Xe
中斷 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
所以我想知道如何根據(?:. )?
, where獲得休息次數
result
應該:
{0: 'ppap', 2: 'pen pineapple apple pen'}
鍵為中斷次數,item為選中元素
這樣我就可以簡單地使用 amin()
來獲得最相關的結果
問題是如何,我需要撰寫自己的函式還是有任何正則運算式模式可以處理這個
uj5u.com熱心網友回復:
您可以使用模塊中的Counter
類collections
來快速消除與前兩個條件不匹配的元素。然后您可以使用SequenceMatcher
fromdifflib
來選擇剩余元素中最相關的選項。
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]))
uj5u.com熱心網友回復:
比較相似字串的另一種可能方法是使用 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 party
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/505887.html
標籤:Python python-3.x 算法 搜索