【问题标题】:Delete a line in multiple text files with the same line beginning but varying line ending using Python v3.5使用 Python v3.5 删除多个文本文件中具有相同行开头但不同行结尾的行
【发布时间】:2016-03-14 05:35:28
【问题描述】:

我有一个充满 .GPS 文件的文件夹,例如1.GPS、2.GPS等... 每个文件中包含以下五行:

Trace #1 at position 0.004610
$GNGSA,A,3,02,06,12,19,24,25,,,,,,,2.2,1.0,2.0*21
$GNGSA,A,3,75,86,87,,,,,,,,,,2.2,1.0,2.0*2C
$GNVTG,39.0304,T,39.0304,M,0.029,N,0.054,K,D*32
$GNGGA,233701.00,3731.1972590,S,14544.3073733,E,4,09,1.0,514.675,M,,,0.49,3023*27

...在接下来的五行中,紧随其后的是具有不同值的相同数据结构:

Trace #6 at position 0.249839
$GNGSA,A,3,02,06,12,19,24,25,,,,,,,2.2,1.0,2.0*21
$GNGSA,A,3,75,86,87,,,,,,,,,,2.2,1.0,2.0*2C
$GNVTG,247.2375,T,247.2375,M,0.081,N,0.149,K,D*3D
$GNGGA,233706.00,3731.1971997,S,14544.3075178,E,4,09,1.0,514.689,M,,,0.71,3023*2F

(我意识到 $GNGSA 行之后的值在上面的示例中没有变化。这只是一个不好的例子......在真实的数据集中它们确实不同!)

我需要删除以“$GNGSA”和“$GNVTG”开头的行(即,我需要从每个 .GPS 文件中的每组五行中删除第 2、3 和 4 行)。

这种五行模式在每个文件中持续不同的次数(对于某些文件,可能只有两个五行组,而其他文件可能有数百个五行组)。因此,根据行号删除这些行将不起作用(因为行号是可变的)。

我遇到的问题(如上面的示例所示)是“$GNGSA”或“$GNVTG”后面的文本不同。

我目前正在学习 Python(我正在使用 v3.5),所以认为这将是一个让我学习一些新技巧的好项目...

我已经尝试过的:

到目前为止,我已经设法创建了循环遍历整个文件夹的代码:

import os

indir = '/Users/dhunter/GRID01/'  # input directory
for i in os.listdir(indir):  # for each "i" (iteration) within the indir variable directory...
    if i.endswith('.GPS'):  # if the filename of an iteration ends with .GPS, then...
        print(i + ' loaded')  # print the filename to CLI, simply for debugging purposes.
        with open(indir + i, 'r') as my_file:  # open the iteration file
            file_lines = my_file.readlines()    # uses the readlines method to create a list of all lines in the file.
            print(file_lines)  # this prints the entire contents of each file to CLI for debugging purposes.

上面的一切都很完美。

我需要什么帮助:

  1. 如何检测和删除行本身,然后保存文件(到相同的位置;无需保存到不同的文件名)?
  2. 文件名 - 通常以“.GPS”结尾 - 有时以“.gps”结尾(唯一的区别是这种情况)。我上面的代码只适用于大写文件。除了完全复制代码和更改 endswith 参数之外,我如何使它适用于这两种情况?

最后,我的文件需要如下所示:

Trace #1 at position 0.004610
$GNGGA,233701.00,3731.1972590,S,14544.3073733,E,4,09,1.0,514.675,M,,,0.49,3023*27
Trace #6 at position 0.249839
$GNGGA,233706.00,3731.1971997,S,14544.3075178,E,4,09,1.0,514.689,M,,,0.71,3023*2F

有什么建议吗?提前致谢。 :)

【问题讨论】:

    标签: python file text editing


    【解决方案1】:

    你快到了。

    import os
    
    indir = '/Users/dhunter/GRID01/'  # input directory
    for i in os.listdir(indir):  # for each "i" (iteration) within the indir variable directory...
        if i.endswith('.GPS'):  # if the filename of an iteration ends with .GPS, then...
            print(i + ' loaded')  # print the filename to CLI, simply for debugging purposes.
            with open(indir + i, 'r') as my_file:  # open the iteration file
                for line in my_file:
                    if not line.startswith('$GNGSA') and not line.startswith('$GNVTG'):
    
                        print(line) 
    

    【讨论】:

    • 啊,当然。旧的“不”想法。傻我!谢谢,阿维纳什。这会将正确的行打印到终端。但是,当我添加到它时: with open(indir + i + 'new.gps', 'w') as my_file2: (new line in code) my_file2.writelines(line)`,它只会删除新文件中的所有内容文件,除了文件中的第一行。
    • 不要使用 writelines,只使用output_fileobj.write(line)
    • 发现时使用with open(indir + i) as my_file, open(indir + i + 'new.gps') out_file:,然后使用out_file.write(line)。此外,if i.lower().endswith('.gps') 会解决您的案例问题。
    • 对不起,Avinash - 我做了一些广泛的谷歌搜索,但不明白你使用 output_fileobj.write(line) 的意思。我也不明白您的解决方案,@tdelaney ...您能否将其发布为新的可能答案,以便我可以看到换行符并询问有关它的具体问题?谢谢。 :)
    • @tdelaney - 谢谢 - 您的解决方案“如果 i.lower().endswith('.gps')”解决了我的案例问题。 :)
    【解决方案2】:

    按照其他人的说法,您走在正确的轨道上!您出错的地方在于区分大小写的文件扩展名检查,以及一次读取整个文件内容(这本身并没有错,但它可能会增加我们不需要的复杂性)。

    我已对您的代码进行了注释,为简单起见删除了所有调试内容,以说明我的意思:

    import os
    
    indir = '/path/to/files'
    for i in os.listdir(indir):
    if i.endswith('.GPS'): #This CASE SENSITIVELY checks the file extension
        with open(indir + i, 'r') as my_file: # Opens the file
            file_lines = my_file.readlines() # This reads the ENTIRE file at once into an array of lines
    

    所以我们需要解决区分大小写的问题,而不是读取所有行,而是逐行读取文件,检查每一行以查看是否要丢弃它,并且将我们感兴趣的行写入输出文件。

    因此,结合@tdelaney 对文件名的不区分大小写的修复,我们将第 5 行替换为

    if i.lower().endswith('.gps'): # Case-insensitively check the file name
    

    我们不会一次读取整个文件,而是遍历文件流并打印出每个所需的行

    with open(indir + i) as in_file, open(indir + i + 'new.gps') as out_file: # Open the input file for reading and creates + opens a new output file for writing - thanks @tdelaney once again!
        for line in in_file # This reads each line one-by-one from the in file
            if not line.startswith('$GNGSA') and not line.startswith('$GNVTG'): # Check the line has what we want (thanks Avinash)
                out_file.write(line + "\n") # Write the line to the new output file
    

    请注意,您应该确保在“for line in in_file”循环的外部打开输出文件,否则该文件将在每次迭代时被覆盖,这将擦除您到目前为止已经写入的内容(我怀疑这是您在之前的答案中遇到的问题)。同时打开两个文件,不会出错。

    或者,您可以在打开文件时指定文件访问模式,根据

    with open(indir + i + 'new.gps', 'a'):
    

    它将以附加模式打开文件,这是一种特殊的写入模式,它保留文件的原始内容,并向其中附加新数据而不是覆盖现有数据。

    【讨论】:

    • 感谢@Sampson 的解释。这现在更有意义了。 :) 但是,我收到“with open(indir + i) as in_file, open(indir + i + 'new.gps') out_file:”行的语法错误 - 错误中的箭头指向最后一个 e in 'out_file:' 在该行的末尾...
    • 对不起,该行缺少第二个“as”,如with open(indir + i) as in_file, open(indir + i + 'new.gps') as out_file: 将更新我的答案。
    • 啊,是的,我在发布第一条评论时也尝试过,但在最后一行尝试时遇到了不同的错误:out_file.write(line) io.UnsupportedOperation: not writable - 可能是权限错误,但我不知道如何修复它。再次感谢您的帮助。 :)
    【解决方案3】:

    好的,根据 Stack Overflow 上的 Avinash Raj、tdelaney 和 Sampson Oliver 的建议,以及另一位私下提供帮助的朋友,以下是目前有效的解决方案:

    import os
    indir = '/Users/dhunter/GRID01/'  # input directory
    for i in os.listdir(indir):  # for each "i" (iteration) within the indir variable directory...
        if i.lower().endswith('.gps'):  # if the filename of an iteration ends with .GPS, then...
            if not i.lower().endswith('.gpsnew.gps'):  # if the filename does not end with .gpsnew.gps, then...
                print(i + ' loaded')  # print the filename to CLI.
                with open (indir + i, 'r') as my_file:
                    for line in my_file:
                        if not line.startswith('$GNGSA'):
                            if not line.startswith('$GNVTG'):
                                with open(indir + i + 'new.gps', 'a') as outputfile:
                                    outputfile.write(line)
                                    outputfile.write('\r\n')
    

    (你会看到我必须添加另一层 if 语句以阻止它使用以前使用脚本“if not i.lower().endswith('.gpsnew.gps') 的输出文件:",但以后使用这些说明的任何人都可以轻松删除此行)

    我们将倒数第三行的打开模式切换为“a”以进行追加,以便将所有正确的行保存到文件中,而不是每次都覆盖。

    我们还在最后一行添加了在每行末尾添加换行符。

    感谢大家的帮助、解释和建议。希望这个解决方案将来对某人有用。 :)

    【讨论】:

      【解决方案4】:

      2。文件名:

      if 接受任何返回真值的表达式,您可以将表达式与标准布尔运算符组合:if i.endswith('.GPS') or i.endswith('.gps')。 您也可以将... and ... 表达式放在if 之后的括号中,这样会更有把握,但这不是必须的。

      或者,作为一种不太通用的解决方案,(但是因为您想学习一些技巧:))在这种情况下您可以使用字符串操作:string 类型的对象有很多方法。 '.gps'.upper() 给了'.GPS'——试试吧,如果你能利用这个! (即使打印的字符串也是字符串对象,但您的变量行为相同)。

      1.寻找线:

      正如您在其他解决方案中看到的那样,您无需读出所有行,您可以检查是否要“即时”使用它们。但我会坚持使用readlines 的方法。它为您提供了一个列表,并且列表支持索引和切片。试试:

      anylist[stratindex, endindex, stride],对于任何值,例如尝试:newlist = range(100)[1::5]

      在交互模式下或在脚本开头尝试简单的基本操作总是有帮助的。这里range(100) 只是一些示例列表。在这里,您可以看到 python for-syntax 的工作原理,与其他语言不同:您可以迭代任何列表,如果您只需要整数,您可以使用 range() 创建一个带有整数的列表。

      所以这将与任何其他列表相同 - 例如你从readlines()得到的那个

      这会从列表中选择一个切片,从第二个元素开始,到最后结束(因为省略了结束索引),并且每第 5 个元素取一个。现在您有了这个子列表,您可以从原始列表中删除它。因此,对于具有范围的示例:

      a = range(100)
      del(a[1::5])
      print a            
      

      因此,您可以看到,相应的项目已被删除。现在对您的file_lines 执行相同操作,然后继续删除您要删除的其他行。

      然后,在一个新的with 块中,打开要写入的文件并执行writelines(file_lines),这样剩余的行就会被写回到文件中。

      当然,您也可以通过for 循环和startswith() 来查找每一行的内容。或者您可以结合这些方法,并检查是否按数字删除行会留下正确的开始,因此如果出现意外情况,您可以打印错误...

      3.保存文件

      readlines() 中保存行后,您可以关闭文件。事实上,这是在with-block 的末尾自动完成的。然后只需以'w' 模式而不是'r' 打开它并执行yourfilename.writelines(yourlist)。你不需要保存,它在关闭时保存。

      【讨论】:

      • 感谢 Ilja 的解释。我了解您的文件名解决方案-效果很好,谢谢。但是,我根本不了解您的其他解决方案。据我所知,您的“mylist [stratindex ...”解决方案要求我为搜索定义一个范围(即如果范围(100),它将仅搜索每个文件的前 100 行......是正确的?如果是这样,我是否应该将该范围设置为例如 100000,这样文件的长度并不重要?我也不明白你的段落“这个.........较短的列表。”你能请澄清一下?再次感谢。:)
      • 啊,对不起,我的例子不起作用……我没注意到,谢谢你的评论。现在我有一些正确的代码,希望也有更好的解释。您从中学到的主要内容是切片列表。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-09-03
      • 2017-02-15
      • 2013-11-27
      • 2014-05-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多