该计划的目的是收集计算机上所有程序的列表,并根据用户输入找到正确的路径。因此,如果输入为Audition
,程序将返回
C:\Adobe\Audition CC 2014\Audition CC 2014.exe
。
我需要它在txt文件中搜索与用户输入最相似的行。我的代码如下:
import os
import subprocess
import getpass
import sys
import difflib
from difflib import SequenceMatcher as SM
user = getpass.getuser()
print(os.getcwd())
exeFile = (os.getcwd() + "/paths/programpaths.txt")
def get_filepaths(directory):
file_paths = [] # List which will store all of the full filepaths.
exes = open(os.getcwd() + "/paths/programpaths.txt", "w+")
# Walk the tree.
for root, directories, files in os.walk(directory):
for filename in files:
# Join the two strings in order to form the full filepath.
filepath = os.path.join(root, filename)
file_paths.append(filepath) # Add it to the list.
if filepath.endswith('exe') and "ninstall" not in filepath and "$RECYCLE.BIN" not in filepath:
files = filepath.encode('cp850', errors='replace').decode('cp850')
#print(files + "\n")
exes.write(files + "\n")
return file_paths # Self-explanatory.
if not os.path.exists(exeFile):
print("List compilation should only happen once")
print()
print("Compiling list of installed programs")
print("This may take a while")
exes = open(os.getcwd() + "/paths/programpaths.txt", "a+")
full_file_pathsx64 = get_filepaths('C:\Program Files')
full_file_pathsx86 = get_filepaths('C:\Program Files (x86)')
full_file_pathsgames = get_filepaths('G:\\')
# Run the above function and store its results in a variable.
print("List compilation should only happen once")
print()
print("Done!")
pinput = input()
for line in open(exeFile):
prog = line.split("\\")[-1]
sim = difflib.get_close_matches(pinput, [prog], 1)
print(sim)
然而,这会打印一个空白括号" []"对于文件中的每一行,并不只是给我一个我需要的那一行。
我知道这是因为我告诉它为每一行做这个,但我不知道如何解决这个问题。
答案 0 :(得分:3)
get_close_matches(…, 1)
调用将返回一个空列表或一个匹配列表。
你想用英语做的是:
将其直接翻译为python:
if sim:
print(sim[0])
(您可以为&#34写else: pass
;否则,不要做任何事情",否则你就不能写任何东西。)
解决了每行不打印[]
的问题,只需打印匹配项#34;
但这引发了另一个问题:你实际上没有得到任何匹配。
正如poke在评论中解释的那样,get_close_matches
的第二个参数是要检查的可能性列表,但是您传递的值prog
是单个字符串。< / p>
如果不清楚为什么它是一个字符串,请看这一行:
prog = line.split("\\")[-1]
您将split
字符串放入较小的字符串列表中,然后只使用[-1]
的最后一个字符串。
如果您很好奇为什么不会收到错误:字符串本身就是一个字符串序列,每个字符一个字符串。因此,如果prog
是"abcde"
,那么您要求它将['a', 'b', 'c', 'd', 'e']
视为5种不同的可能性,这是完全合理的事情,它不仅仅是{&1;}。可能永远匹配任何东西。
我想想你想要的东西可能只是传递了这个可能性的列表:
sim = difflib.get_close_matches(pinput, [prog], 1)
或者,或者,不是一次只搜索每种可能性,而是建立一个包含所有可能性的大清单,然后一次搜索所有可能性:
progs = []
for line in open(exefile):
progs.append(line.split("\\")[-1])
sim = difflib.get_close_matches(pinput, progs, 1)
但是在整个文件中只有1个匹配,而不是每行可能匹配1个。如果你想要更多超过1,你可以做到这一点,但我不确定它与大量的数据有多好。 (你总是可以尝试看看。)
无论如何,希望你能理解你真正想要的东西而且不必猜测。 :)
答案 1 :(得分:1)
根据您现在发布的完整代码,这是我的解决方案,可能最好地解决您的问题:
with open(exeFile) as f:
programs = { path.rsplit('\\', 1)[-1].rstrip()[:-4].lower(): path.strip() for path in f }
sim = difflib.get_close_matches(pinput.lower(), programs.keys(), 1)
if sim:
print(programs[sim[0]])
魔法发生在字典理解中。对于文件中的每个path
,我们生成以下名称作为字典条目的键:
path.rsplit('\\', 1)[-1][:-4].lower()
因此,假设像C:\Adobe\Audition CC 2014\Audition CC 2014.exe
这样的文件路径,它首先会通过斜杠从正确的分割并获取最后一个元素,因此我们将获得Audition CC 2014.exe
。接下来,我们剥离空格,然后根据我们生成exefile的方式,我们知道的.exe
是文件名的一部分。所以我们有Audition CC 2014
。接下来,我们对此进行小写,以便我们得到更好的可比性(因为difflib
区分大小写)。
在比较中,我们只是从字典的键中获得紧密匹配(这只是较低的程序名称)。我们将其与较低的用户输入进行比较。
获得结果后,我们会打印属于匹配键的路径。这就是为什么我们在上面建一个字典的原因;否则我们将不得不再次搜索文件以找到完整路径。
答案 2 :(得分:0)
总是很了解你实际上想要做什么
首先定义你的意思&#34;最接近&#34; (通常使用字符串这称为汉明距离)
def hamming_distance(s1,s2):
#first elimate non-letters
s1 = re.sub("[^a-zA-Z]","",s1)
s2 = re.sub("[^a-zA-Z]","",s2)
#the distance is the sum of all instance with differing letters in this case
return sum(a!=b for a,b in izip_longest(s1,s2))
然后你只需要迭代文件并找到&#34;最接近的匹配&#34;
user_input = input("Enter String:")
print(min(open("file_of_strings.txt"),key=lambda x:hamming_distance(x,user_input)))
粗略的,一旦你理解了魔法,你就可以使用difflib获得边际加速
答案 3 :(得分:0)
如果您的exefile
候选列表很小,则将它们预先加载到内存中(在列表中),然后执行difflib.get_close_matches
,例如:
import difflib
with open(exefile) as fin:
progs = [line.rpartition('\\', line)[2] for line in fin]
sim = difflib.get_close_matches(pinput, progs, 1)
如果它非常大并且你不能支持RAM,那么使用heapq:
import difflib, heapq
with open(exefile) as fin:
progs = (line.rpartition('\\'), line)[2] for line in fin)
sim = heapq.nlargest(1, progs, key=lambda L: difflib.SequenceMatcher(None, pinput, L))
答案 4 :(得分:0)
我查找了get_close_matches()的文档。似乎第二个参数应该是list,所以你的代码可以写成:
for line in open(exefile):
prog = line.split("\\")[-1]
prog = [item for item in prog.split(' ')]
sim = difflib.get_close_matches(pinput, prog, 1)
print(sim)
答案 5 :(得分:0)
试试这个:
with open(exefile) as f:
possibilities = [line.split("\\")[-1].rstrip("\n") for line in f]
print(difflib.get_close_matches(pinput, possibilities, 1, 0)[0])
这里的关键是get_close_matches根本不需要返回任何匹配项。来自文档:
get_close_matches(单词,可能性[,n] [,cutoff])
cutoff(默认值为0.6)是[0,1]范围内的浮点数。不会得到至少与单词类似的得分的可能性将被忽略。
因此,如果您使用cutoff=0
,则get_close_matches必须返回一些内容 - 最佳匹配。