【问题标题】:Code for coyping specific lines from multiple files to a single file (and removing part of the copied lines)用于将特定行从多个文件复制到单个文件的代码(并删除部分复制的行)
【发布时间】:2015-07-05 16:13:03
【问题描述】:

首先,我对此真的很陌生。在过去的几天里,我一直在阅读一些教程,但现在我想实现的目标碰壁了。

给你一个长版本:我在一个目录中有多个文件,所有文件都包含某些行(23-26)中的信息。现在,代码必须找到并打开所有文件(命名模式:*.tag),然后将第 23-26 行复制到一个新的单个文件中。 (并在每个新条目后添加一个新行......)。 (可选)它还会从我不需要的每一行中删除一个特定部分:

  • C12b2

    -> C12b2(或类似)之前的所有内容都需要删除。

    到目前为止,我已经设法将这些行从一个文件复制到一个新文件,但其余部分仍然让我无法理解:(不知道格式化是如何工作的)

    f = open('2.tag')     
    
    n = open('output.txt', 'w')
    
    for i, text in enumerate(f):
    
        if i >= 23 and i < 27:
    
            n.write(text)
    
        else:
    
            pass
    

    谁能给我一些建议?我不需要完整的代码作为答案,但是,似乎很难找到不跳过解释的好教程。

  • 【问题讨论】:

    • 除了打线你还想做什么?
    • 我必须承认,当我第一次阅读您的问题时,我的想法是“您使用 python 吗?”因为如果我遇到了你的问题,我可能会尝试使用 sed 进行文件操作,然后将我希望 python 处理的行通过管道传递给 python。
    • 如果您在 *nix 类型系统上,使用 awk 实际上更容易描述您所描述的内容。
    • 您的第二个要求:“需要删除 C12b2(或类似)之前的所有内容”需要对字符串进行进一步解释/规范。
    • 要删除的字符串如下所示:
    • 。它在每个新行的开头重复。

    标签: python python-3.x


    【解决方案1】:

    您可以查看glob 模块,它提供了与您提供的模式匹配的文件名列表,请注意此模式不是正则表达式,它是 shell 样式的模式(使用 shell 样式的通配符)。

    glob 示例 -

    >>> import glob
    >>> glob.glob('*.py')
    ['a.py', 'b.py', 'getpip.py']
    

    然后您可以遍历 glob.glob() 函数返回的每个文件。

    对于每个文件,您都可以执行您现在正在执行的操作。

    然后在写文件的时候,可以用str.find()找到字符串C12b2的第一个实例,然后用slicing去掉不需要的部分。

    举个例子-

    >>> s = "asdbcdasdC12b2jhfasdas"
    >>> s[s.find("C12b2"):]
    'C12b2jhfasdas'
    

    你可以为你的每一行做类似的事情,请注意如果用例只有一些行会有C12b2,那么你需要先检查该字符串是否存在于行中,然后再进行上述切片.示例 -

    if 'C12b2' in text:
        text = text[text.find("C12b2"):]
    

    您可以在将行写入输出文件之前执行上述操作。

    另外,最好看看with 语句,你可以用它来打开文件,这样当你完成处理时它会自动处理关闭文件。

    【讨论】:

    • 感谢您的解释!关于“c12b2”部分:这只是一个例子,问题是事实上我不知道 23-26 的每一行实际上包含什么(除了我想要删除的字符串)。
    • 您想要删除字符串之前的所有内容对吗?
    • 这是一个示例:如果提取的(或将要提取的)行之一如下所示:
    • C13b2 那么我希望从每一行中删除 C13b2 前面的所有内容(始终是模式
    • )。但是,该模式之后的内容总是会有所不同,因此我无法在代码中事先指定。
  • 好的,那只是我的无能;P感谢代码和解释;)
  • 【解决方案2】:

    除了os,不导入任何东西:

    #!/usr/bin/env python3
    import os
    # set the directory, the outfile and the tag below
    dr = "/path/to/directory"; out = "/path/to/newfile"; tag = ".txt"
    
    for f in [f for f in os.listdir(dr) if f.endswith(".txt")]:
        open(out, "+a").write(("").join([l for l in open(dr+"/"+f).readlines()[22:25]])+"\n")
    

    它的作用

    和你描述的完全一样,它:

    • 从目录中的所有文件(即:具有已定义扩展名的文件)中收集已定义的行区域
    • 将各个部分粘贴到一个新文件中,用新行分隔

    说明

    [f for f in os.listdir(dr) if f.endswith(".tag")]
    

    列出您目录中特定扩展名的所有文件,

    [l for l in open(dr+"/"+f).readlines()[22:25]]
    

    读取文件的选定行

    open(out, "+a").write()
    

    写入输出文件,如果不存在则创建它。

    如何使用

    • 将脚本复制到一个空文件中,保存为collect_lines.py
    • 在 head 部分设置包含文件的目录、新文件的路径和扩展名
    • 使用命令运行它:

      python3 /path/to/collect_lines.py
      

    详细版本,带解释

    如果我们“解压”上面的代码,会发生这样的事情:

    #!/usr/bin/env python3
    import os
    #--- set the path to the directory, the new file and the tag below
    dr = "/path/to/directory"; out = "/path/to/newfile"; tag = ".txt"
    #---
    
    files = os.listdir(dr)
    for f in files:
        if f.endswith(tag):
            # read the file as a list of lines
            content = open(dr+"/"+f).readlines()
            # the first item in a list = index 0, so line 23 is index 22
            needed_lines = content[22:25]
            # convert list to string, add a new line
            string_topaste = ("").join(needed_lines)+"\n"
            # add the lines to the new file, create the file if necessary
            open(out, "+a").write(string_topaste)
    

    【讨论】:

    • 感谢您的解释,即使是新手也能理解!;)代码工作得很好。现在我只需要找出如何删除正在复制到新文件中的字符串的一部分。到目前为止,我有:“pattern = '
    • 'lines = content[22:27] clean_lines = [line.split(pattern, 1)[- 1] 用于行中行]"。但它并没有真正做任何事情。 "str.strip([chars])" 在这里可能也无济于事,因为那样我就必须在不需要的部分 (?) 之前或之后定义字符串。
  • @Jonnecy 你能描述一下这个模式吗?特别是C12b2 我在我的代码中有它,直到我读到:(or similar) :)
  • 这是一个示例行:
  • C13b2。现在,我需要保留 c13b2(或第一个模式之后的任何内容,即我无法指定应该保留的内容),并且模式
  • (在输出文件中每个新行的开头重复)要删除。
  • @Jonnecy 我现在必须运行,将添加其他信息 :)
  • 【解决方案3】:

    您可以 realineswritelines 使用 ab 作为要写入的行的边界:

    with open('oldfile.txt', 'r') as old:
        lines = old.readlines()[a:b]
    
    with open('newfile.txt', 'w') as new:
        new.writelines(lines)
    

    【讨论】:

    • 听起来很有趣!但是如果我要提取的行如下所示,我将如何实现它:“
    • {London, British Library, Cotton Caligula A ix, The猫头鹰和夜莺,语言 1=}
    • C13b2
    • 390 262 N
    • {=Central Worcs=}
    • {=示例标记: fols. 233r-239v 第 13 行;240r 第 6-241v 第 15 行,}"。 --------> "
    • " 总是在新行的开头。
    【解决方案4】:

    使用glob package,您可以获得所有*.tag 文件的列表:

    import glob
    # ['1.tag', '2.tag', 'foo.tag', 'bar.tag']
    tag_files = glob.glob('*.tag')
    

    如果您使用with statement 打开文件,它会在之后自动关闭:

    with open('file.tag') as in_file:
        # do something
    

    使用readlines() 将整个文件读入行列表,然后可以对其进行切片:

    lines = in_file.readlines()[22:26]
    

    如果您需要跳过特定模式之前的所有内容,请使用str.split() 分隔模式处的字符串并取最后一部分:

    pattern = 'C12b2'
    clean_lines = [line.split(pattern, 1)[-1] for line in lines]
    

    看看这个例子:

    >>> lines = ['line 22', 'line 23', 'Foobar: C12b2 line 24']
    >>> pattern = 'C12b2'
    >>> [line.split(pattern, 1)[-1] for line in lines]
    ['line 22', 'line 23', ' line 24']
    

    【讨论】:

    • 感谢您的建议!这段代码可以按原样使用,还是我必须添加/修改任何东西?目前它在第 8 行返回一个 SyntaxError(没有第 8 行)。
    • 您是如何尝试运行此代码的?这些 sn-ps 仍然需要放在一起:生成 *.tag 文件列表(第一个块),迭代它(for fname in tag_files:),打开文件(第二个块),读取并“清理”行(第三个和第四块)并使用writelines()clean_lines列表保存到文件中
    • hm,生成所有 *.tag 文件的列表的问题在于它并没有真正使它变得容易得多,因为有几十上百个。我找到了一种提取相关行的方法;现在剩下的是从每个提取的行中删除不需要的字符串。这些字符串始终遵循相同的模式(即它们始终相同),但是,该字符串之后的任何内容都不是我可以事先指定的。它只需要找到该字符串的所有实例并将其删除。
    • 您可以使用glob.glob('*.tag') 生成标记文件列表,无需手动工作:-) - 要删除不需要的字符串,请查看我添加到答案中的示例
    猜你喜欢
    相关资源
    最近更新 更多
    热门标签