我正在 Python 2.7.1 ,我正在尝试识别不包含某些文本字符串的所有文本文件。
该程序似乎首先工作,但每当我将文本字符串添加到文件时,它就会不断出现,好像它不包含它(误报)。当我检查文本文件的内容时,字符串显然存在。
我试着写的代码是
def scanFiles2(rdir,sstring,extens,start = '',cSens = False):
fList = []
for fol,fols,fils in os.walk(rdir):
fList.extend([os.path.join(rdir,fol,fil) for fil in fils if fil.endswith(extens) and fil.startswith(start)])
if fList:
for fil in fList:
rFil = open(fil)
for line in rFil:
if not cSens:
line,sstring = line.lower(), sstring.lower()
if sstring in line:
fList.remove(fil)
break
rFil.close()
if fList:
plur = 'files do' if len(fList) > 1 else 'file does'
print '\nThe following %d %s not contain "%s":\n'%(len(fList),plur,sstring)
for fil in fList:
print fil
else:
print 'No files were found that don\'t contain %(sstring)s.'%locals()
scanFiles2(rdir = r'C:\temp',sstring = '!!syn',extens = '.html', start = '#', cSens = False)
我想代码中有一个缺陷,但我真的没有看到它。
更新
代码仍会出现许多误报:执行的文件包含搜索字符串但被识别为不包含搜索字符串。
文字编码可能会成为问题吗?我用U
作为搜索字符串的前缀来考虑Unicode编码,但它没有任何区别。
Python是否以某种方式缓存文件内容?我不这么认为,但这可能会导致文件在纠正后仍然弹出。
某种恶意软件会导致这些症状吗?对我来说似乎不太可能,但我有点想要解决这个问题。
答案 0 :(得分:12)
在迭代列表时修改元素会导致意外结果:
例如:
>>> lst = [1,2,4,6,3,8,0,5]
>>> for n in lst:
... if n % 2 == 0:
... lst.remove(n)
...
>>> lst
[1, 4, 3, 0, 5]
解决方法迭代复制
>>> lst = [1,2,4,6,3,8,0,5]
>>> for n in lst[:]:
... if n % 2 == 0:
... lst.remove(n)
...
>>> lst
[1, 3, 5]
或者,您可以附加有效的文件路径,而不是从整个文件列表中删除。
修改后的版本(附加文件不是contian sstring
而不是删除):
def scanFiles2(rdir, sstring, extens, start='', cSens=False):
if not cSens:
# This only need to called once.
sstring = sstring.lower()
fList = []
for fol, fols, fils in os.walk(rdir):
for fil in fils:
if not (fil.startswith(start) and fil.endswith(extens)):
continue
fil = os.path.join(fol, fil)
with open(fil) as rFil:
for line in rFil:
if not cSens:
line = line.lower()
if sstring in line:
break
else:
fList.append(fil)
...
list.remove
需要O(n)时间,而list.append
需要O(1)。见Time Complexity。with
声明。答案 1 :(得分:1)
Falsetru已经向你展示了为什么你不应该在循环中删除列表中的行;如果缩短列表,列表迭代器不会也不能更新它们的计数器,因此如果处理了项目3但是您删除了该项目,则下一个迭代项目4之前位于索引5处。
使用fnmatch.filter()
和any()
列出理解版本,使用过滤器lambda
进行不区分大小写的匹配:
import fnmatch
def scanFiles2(rdir, sstring, extens, start='', cSens=False):
lfilter = sstring.__eq__ if cSens else lambda l, s=sstring.lower(): l.lower() == s
ffilter = '{}*{}'.format(start, extens)
return [os.path.join(r, fname)
for r, _, f in os.walk(rdir)
for fname in fnmatch.filter(f, ffilter)
if not any(lfilter(l) for l in open(os.path.join(root, fname)))]
但也许你最好坚持一个更易读的循环:
def scanFiles2(rdir, sstring, extens, start='', cSens=False):
lfilter = sstring.__eq__ if cSens else lambda l, s=sstring.lower(): l.lower() == s
ffilter = '{}*{}'.format(start, extens)
result = []
for root, _, files in os.walk(rdir):
for fname in fnmatch.filter(files, ffilter):
fname = os.path.join(r, fname)
with open(fname) as infh:
if not any(lfilter(l) for l in infh):
result.append(fname)
return result
答案 2 :(得分:1)
另一个打开搜索使用正则表达式的替代方法(虽然只使用grep
使用适当的选项仍然会更好):
import mmap
import os
import re
import fnmatch
def scan_files(rootdir, search_string, extension, start='', case_sensitive=False):
rx = re.compile(re.escape(search_string), flags=re.I if not case_sensitive else 0)
name_filter = start + '*' + extension
for root, dirs, files in os.walk(rootdir):
for fname in fnmatch.filter(files, name_filter):
with open(os.path.join(root, fname)) as fin:
try:
mm = mmap.mmap(fin.fileno(), 0, access=mmap.ACCESS_READ)
except ValueError:
continue # empty files etc.... include this or not?
if not next(rx.finditer(mm), None):
yield fin.name
如果您想要实现名称,请使用list
,或者像对待任何其他生成器一样对待它...
答案 3 :(得分:1)
请不要为此编写python程序。这个程序已经存在。使用grep:
grep * -Ilre 'main' 2> /dev/null
99client/.git/COMMIT_EDITMSG
99client/taxis-android/build/incremental/mergeResources/production/merger.xml
99client/taxis-android/build/incremental/mergeResources/production/inputs.data
99client/taxis-android/build/incremental/mergeResources/production/outputs.data
99client/taxis-android/build/incremental/mergeResources/release/merger.xml
99client/taxis-android/build/incremental/mergeResources/release/inputs.data
99client/taxis-android/build/incremental/mergeResources/release/outputs.data
99client/taxis-android/build/incremental/mergeResources/debug/merger.xml
99client/taxis-android/build/incremental/mergeResources/debug/inputs.data
(...)
http://www.gnu.org/savannah-checkouts/gnu/grep/manual/grep.html#Introduction
如果你需要python中的列表,只需从中执行grep并收集结果。