该程序的目的是收集计算机上所有程序的列表,并根据用户输入找到正确的路径。因此,如果输入为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)但是,这会为文件中的每一行打印一个空方括号"[]“,而不只是给出我需要的那一行。
我知道这是因为我告诉它对每一行都这样做,但我不知道如何解决这个问题。
发布于 2015-04-18 07:25:39
get_close_matches(…, 1)调用将返回一个空列表,或者只返回一个匹配项的列表。
用英语来说,你想要做的是:
将其直接转换为python:
if sim:
print(sim[0])(您可以编写else: pass来表示“否则,什么都不要做”,也可以什么都不写。)
这解决了“不要打印每一行的[],只打印匹配的内容”的问题。
但这又带来了另一个问题:你实际上没有得到任何匹配。
正如poke在注释中解释的那样,get_close_matches的第二个参数是一个要检查的可能性列表,但是您传递的值prog是一个单独的字符串。
如果不清楚为什么它是单个字符串,请看下面这一行:
prog = line.split("\\")[-1]您将字符串split到一个较小的字符串列表中,然后使用[-1]只获取最后一个字符串。
如果您很好奇为什么没有得到一个错误:字符串本身就是一个字符串序列,每个字符对应一个字符串。因此,如果prog是"abcde",那么您要求它将['a', 'b', 'c', 'd', 'e']视为5种不同的可能性,这是非常合理的做法,只是它不太可能匹配任何东西。
我认为您在这里需要的可能只是传递这一可能性的列表:
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个总数,你可以这样做,但我不确定它对一个巨大的数字有多好。(您可以随时尝试并查看。)
无论如何,希望你知道你真正想要的是什么,而不是去猜测。:)
发布于 2015-04-18 19:50:20
基于你现在发布的完整代码,这是我的解决方案,可能是解决你问题的最好方法:
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区分大小写)。
在比较中,我们只需从字典的键(这只是小写的程序名)中获得最接近的匹配项。我们将其与大小写较低的用户输入进行比较。
一旦我们得到一个结果,我们打印属于匹配关键字的路径。这就是我们在上面构建字典的原因;否则我们将不得不再次搜索文件以找到完整路径。
发布于 2015-04-18 07:31:25
理解你真正想要做的事情总是很好的
首先定义你所说的“最近”是什么意思(对于字符串,这通常被称为汉明距离)
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))然后,您只需遍历文件并找到“最接近的匹配”
user_input = input("Enter String:")
print(min(open("file_of_strings.txt"),key=lambda x:hamming_distance(x,user_input)))粗略一旦你理解了魔术,你可能会用difflib获得一个边际加速。
https://stackoverflow.com/questions/29710979
复制相似问题