我是python的新手,我每天都学到很多东西。 我想做一个自动脚本,可以帮助我完成工作。
我有一个包含一些文件的特定文件夹,我不希望我的工具是特定于文件的,因为我想重用这个脚本,所以我希望它在文件中查找特定的标题,
让我们说该文件位于“路径”中间的某个位置,并且在其下面有许多路径,例如“file path =”某些路径“
我希望我的脚本转到我指定的目录并查找包含此标题“path”的文件 复制其中一条路径(它们就在它下面),就是这样。
然后我将使用此路径下载文件和更多,但这部分我已经完成。 我只是不知道如何在给出特定文件夹时查找文件中的特定字符串并复制我想要的字符串。
所以我说我有一个文件夹(C:\ Folder) 在文件夹中我有3个文件(1,2,3)
我想找一个包含这种模式“路径”的文件 并复制路径或至少其中一个在其下指定的路径。 他们会像“文件路径= C:\ somepath” 所以文件内容就像
布拉布拉
布拉布拉
路径
文件路径= C:\ somepath
文件路径= C:\ somepath2
布拉布拉
我想复制C:\ somepath并将其用作我工作的一部分。
非常感谢所有助手,这对我来说非常重要。
答案 0 :(得分:1)
第一步是查看目录中的所有文件。那是os.listdir
。
接下来,您需要在循环中打开每个文件。所以,到目前为止,我们已经:
for filename in os.listdir(directory):
with open(filename) as f:
现在,我们如何处理每个文件?有几个不同的选项 - 我们可以在整个文件中读取(或mmap
它)然后使用str.find
或正则表达式方法来解析它,或者我们可以一行一行地跟踪我们的状态,或者我们可以使用itertools
函数转换行序列,或者我们可以构建一个状态机并运行它,或者......
我认为新手最简单的方法是手动逐行。但是让我们把它包装在一个函数中。所以:
def parse_file(f):
paths = []
found_paths = False
for line in f:
line = line.strip()
if not found_paths:
if line == 'paths':
found_paths = True
else:
if line.startswith('file path='):
paths.append(line[len('file path='):])
else:
break
return paths
paths = []
for filename in os.listdir(directory):
with open(filename) as f:
paths.append(parse_file(f))
找到第一行后如何停止?
阅读第一行后只需break
。所以,而不是:
if line.startswith('file path='):
paths.append(line[len('file path='):])
else:
break
这样做:
if line.startswith('file path='):
paths.append(line[len('file path='):])
break
我如何修复它以将路径放在字典中的不同索引中,因为它将所有路径放在第一个字段中
嗯,现在,你不创建一个字典,你正在创建一个列表。
如果你想要一本字典,比如将每个文件映射到该文件中的文件路径列表,这很容易。而不是:
paths = []
for filename in os.listdir(directory):
with open(filename) as f:
paths.append(parse_file(f))
这样做:
paths = {}
for filename in os.listdir(directory):
with open(filename) as f:
paths[filename] = parse_file(f)
但是,如果您只想要一个值,那么首先不构建列表可能会更简单。如果你找到一个路径名,你只需要返回路径名,如果不这样的话,你需要返回路径名(如None
)。
我如何修改有问题的路径。因为文件中的路径以这种格式保存 - 我只想复制C:\ folder \ folder
嗯,首先,我的代码甚至找不到任何格式的内容。您要求查找file path=…
之类的行,因此我使用了startswith
,但<file path=
并未启动。因此,您首先需要更改您检查的startswith
。同时,您还需要处理引号和尖括号。
此时,看起来只是愚蠢的文本处理可能不是正确的答案。这看起来像XML。解析XML文档的最简单方法是使用XML解析器,如xml.elementtree
。如果它不是XML文档,只是一个基于行的文档,其中包含XML节点,那么 仍然可以尝试将每一行解析为XML文档,但它可能更容易使用{{ 1}}使用合适的正则表达式(例如,re
将仅匹配引号之间的部分)。在不知道你的实际输入文本是什么样的情况下,我不能给你任何比这更具体的内容。
最后,在完成该步骤之后,看起来您想要删除目录路径的尾部反斜杠,因此即使文件具有r'<file path="(.*?)"/>'
,您也会获得C:\folder\folder
。您可以使用C:\folder\folder\
中的函数,但如果您确定路径将始终采用Windows格式,则可以更简单地告诉它使用os.path
删除任何尾部反斜杠。 (注意那里的双反斜杠,因为你需要在Python字符串中转义反斜杠。)
答案 1 :(得分:-1)
根据您的评论,您的数据实际上是XML,您想要的是第一个path
节点中每个(或第一个)file
节点的paths
属性。
这实际上更容易编写 - 并且在XML解析器方面更加健壮。
例如,这些可能都是有效的file
个节点:
<file path="C:\Foo\Bar" />
<file path="C:\Baz\Qux"/>
<file path="C:\Foo\Bar" />
<file path="C:\Spam\Eggs\" alt="other attribute cruft" />
<file alt="other attribute cruft" path="C:\Spam\Eggs\" />
<file path="C:\Spam\Spam\"></file>
你甚至可以看到这些,合法与否:
<file path='C:\Eggs\"Spam Spam Spam"\"Spammity Spam"'/>
您不想尝试以纯文本处理所有这些可能性。但如果你不处理所有这些 - 除此之外 - 墨菲定律保证你最终会遇到一个文件,里面有你不能处理的文件。
有很多不同的XML解析器,甚至内置在标准库中,但我认为最简单的是ElementTree。所以:
import os
import os.path
import xml.etree.ElementTree as ET
filepaths = {}
for filename in os.listdir(directory):
try:
doc = ET.parse(os.path.join(directory, filename))
paths = doc.find('paths')
filepaths[filename] = [f.attrib['path'] for f in paths.findall('file')]
except Exception as e:
# You may want to log something, treat different exceptions differently, etc.
pass
应该很容易弄清楚如何更改它以处理所有paths
节点而不是file
下的第一个节点或第一个paths
节点而不是所有节点,或具有file
属性等的第一个path
节点
如果您使用的是Python 2.x,并且文件非常大,这可能会很慢。但您可以通过明确使用cElementTree
来解决这个问题。这样做很常见:
try:
import xml.etree.cElementTree as ET
except ImportError:
import xml.etree.ElementTree as ET
如果可能的话,这将给你快速的“C”实现,否则,CPython 2.5+(包括3.x,两者合并在一起),PyPy等等的慢速提供。
同时,从其他评论中,您要求提供原始帖子中没有的其他内容:
我只需要......将反斜杠改为/
这很容易。只需在每条路径s.replace('\\', '/')
上致电s
。
但是,这有点奇怪。反之亦然(它甚至内置于标准库中 - os.path.normpath
将在POSIX上单独留下斜线,但在Windows上将它们转换为反斜杠),但从原生Windows到POSIX通常是一个更大的操作,比如构建一个URL ......在这种情况下,你可能想要使用一个更高级别的函数。
在文件中 - 我想要的结果是C:\ folder \ folder
在这里,听起来你想要去除任何尾随反斜杠。同样,这是一个奇怪的事情,你可能真的想做一些比这更高级的事情(比如os.path.dirname
可能?),但很简单:s.rstrip('\\')
。
当然最后两个相互矛盾 - 如果您想要的结果是C:\folder\folder
,并且您将反斜杠转换为正斜杠,那么您将无法获得所需的结果。
但希望我已经给了你足够的东西来构建你真正想要的东西。