原帖发帖人希望用 Python 匹配两个文件的内容,并将输出结果写到一个文件中。第一个文件包含数千行文件名(称为 sNotUsed 文件),第二个文件包含大约 50 个 XML 文件。XML 文件可能包含数千行,并且遵循标准的 XML 格式。
原帖发帖人分享了代码的片段,但最后一行应该至少打印一次,但实际上并没有打印。
原帖发帖人希望脚本逐行遍历每个 XML 文件,并查看该行中的文件名部分是否与 sNotUsed.txt 文件的行完全匹配。如果有匹配项,则将其从 XML 中删除。如果该行与 sNotUsed.txt 文件中的任何行都不匹配,则希望将其作为新修改的 XML 文件(将覆盖旧文件)的输出的一部分。
2、解决方案
问题分析
原帖发帖人代码中的问题主要有以下几个方面:
-
使用
open()函数打开文件时,没有使用with语句。with语句可以确保文件在使用后被正确关闭,即使在发生异常时也是如此。 -
在使用正则表达式匹配文件名时,没有将正则表达式编译成模式对象,而是直接将正则表达式字符串传递给
findall()函数。编译正则表达式可以提高匹配效率。 -
在打开 XML 文件时,没有指定编码,这可能会导致 Unicode 编码错误。
-
在写入 XML 文件时,没有使用
codecs.open()函数,这可能会导致 Unicode 编码错误。 -
在使用
os.listdir()函数时,没有将目录的绝对路径传递给该函数,而是传递了目录名,这可能会导致问题。
解决方法
以下是原帖发帖人代码的修改版本,修复了上述问题:
import os
import re
import codecs
sFile = open("C:\Users\xxx\Desktop\sNotUsed.txt", "r") # open sNotUsed txt file
sNotUsed=sFile.readlines() # read all lines and assign to list
sFile.close() # close file
search = re.compile(r"\w/([\w-]+)")
sNotUsed=[x.strip().replace(',','') for x in sNotUsed]
directory=r'C:\Users\xxx\Desktop\dir'
filelist=os.listdir(directory) # getting the list of xmlFiles
# for each file in the list
for files in filelist:
if files.endswith('.xml'): # make sure it is an XML file
xmlFile = codecs.open(os.path.join(directory, files), "r", encoding="UTF-8") # open first file with read
xmlComp = xmlFile.readlines() # read lines and assign to list
print xmlComp
xmlFile.close() # closing the file since the lines have already been read and assigned to a variable
xmlEdit = codecs.open(os.path.join(directory, files), "w", encoding="UTF-8") # opening the same file again and overwriting all existing lines
for lines in xmlComp: # iterate by line in list of lines
#headerInd = re.search(search, lines) # used to get the headers, comments, and ending blocks
temp = re.findall(search, lines) # finds all strings that match the regular expression compiled above and makes a list for each
if temp: # if the list is not empty
if temp[0] not in sNotUsed: # if the first (and only) value in each list is not in the sNotUsed list
xmlEdit.write(lines) # write it in the file
else: # if the list is empty
xmlEdit.write(lines) # write it (used to preserve the beginning and ending blocks of the XML, as well as comments)
代码说明
sNotUsed变量是一个列表,存储了sNotUsed.txt文件中的所有行。search变量是一个正则表达式模式对象,用于匹配 XML 文件中的文件名。sNotUsed变量中的每一行都被剥离了多余的空格并替换了逗号,以确保与 XML 文件中的文件名进行准确匹配。directory变量存储了 XML 文件所在的目录的绝对路径。filelist变量是一个列表,存储了directory目录中所有以.xml结尾的文件名。- 对于
filelist中的每个文件名,都会打开相应的 XML 文件并将其内容读取到xmlComp变量中。 xmlFile变量被关闭,以释放系统资源。- 打开同一个 XML 文件进行写入,并将现有内容全部覆盖。
- 对于
xmlComp中的每一行,都会使用正则表达式查找文件名。如果找到文件名,并且该文件名不在sNotUsed列表中,则将该行写入 XML 文件。 - 如果没有找到文件名,或者文件名在
sNotUsed列表中,则将该行写入 XML 文件,以保留 XML 文件的开头和结尾块以及注释。
代码示例
假设 sNotUsed.txt 文件的内容如下:
fileNameWithoutExtension1
fileNameWithoutExtension2
fileNameWithoutExtension3
假设 dir 目录中有一个名为 file1.xml 的 XML 文件,其内容如下:
<blocks>
<more stuff="name">
<Tag2>
<Tag3 name="Tag3">
<!--COMMENT-->
<fileType>../../dir/fileNameWithoutExtension1</fileType>
<fileType>../../dir/fileNameWithoutExtension4</fileType>
</blocks>
运行上述修改后的代码后,file1.xml 文件的内容将变为:
<blocks>
<more stuff="name">
<Tag2>
<Tag3 name="Tag3">
<!--COMMENT-->
<fileType>../../dir/fileNameWithoutExtension4</fileType>
</blocks>
因为 fileNameWithoutExtension1 在 sNotUsed.txt 文件中,所以它被从 XML 文件中删除了。