【问题标题】:How to remove starting newlines or the starting new from a binary file?如何从二进制文件中删除开始换行符或开始新行?
【发布时间】:2020-05-04 19:46:30
【问题描述】:

我看到有关于删除尾随换行符的讨论。

How can I delete a newline if it is the last character in a file?

但我没有找到关于删除起始换行符的讨论。任何人都可以让我知道删除开始换行符的最佳方法是什么(首选一个班轮)?谢谢。

【问题讨论】:

  • lstrip() ? replace也可以帮忙
  • 您要删除所有初始空行,还是只删除第一个空行?
  • 两者都需要。
  • 你能举一个小的输入例子吗?
  • 另外,为什么首选一个班轮

标签: python shell perl sed command-line


【解决方案1】:

chomp 等效的相反Perl 代码是s/^\n//。不要在最后一行 (eof) 上做,而是在第一行做。即使它只是一个空行,删除换行符将意味着该行不会在输出中打印任何内容。

perl -pe 's/^\n// if $. == 1' filename >filename2

或就地:

perl -pi -e 's/^\n// if $. == 1' filename

由于开始换行符定义为空行,因此您也可以使用 -n 而不是 -p 跳过打印它们(行为相同但不打印,因此您可以确定要打印哪些行)。

perl -ni -e 'print unless $. == 1 and m/^\n/' filename

如果您想删除潜在的多个起始换行符,您可以采取另一种方法;开始时自己推进句柄,直到收到非空行。

perl -pi -e 'if ($. == 1) { $_ = <> while m/^\n/ }' filename

如果您不介意一次将整个文件读入内存而不是逐行读入内存,这一切都会容易得多:

perl -0777 -pi -e 's/^\n+//' filename

为了避免在编辑文件时做任何多余的工作,除非它以换行符开头,您可以通过在编辑前加上另一个命令来调节编辑(读取文件的第一行,如果没有,则导致非零退出状态以换行符开始):

perl -e 'exit 1 unless <> =~ m/^\n/' filename && perl ...

【讨论】:

  • 不要替换,如果只是换行,则跳过该行。
  • 但我想这需要使用除了简单的perl -pie 循环之外的其他东西。
  • @Barmar 是的,你不能跳过-p 中的行,因为$_ 总是被打印出来。但是您可以使用-n 采取这种方法 - 会增加答案。
  • 另外,问题说开始换行 - 复数。不过,我要求澄清。
  • 我不太关注这个perl -pi -e 'if ($. == 1) { $_ = &lt;&gt; while m/^\n/ }' filename。你能解释一下它是如何工作的吗?谢谢。
【解决方案2】:

在 Python 中,开始读取文件而不是循环写入,直到出现非空行。

outdata = ""
with open(filename) as infile:
    while True:
        line = infile.readline()
        if line != "\n":
            break
    if line:
        outdata = line # save first non-empty line
    outdata += infile.read() # save the rest of the file
with open(filename, "w") as outfile:
    outfile.write(outdata)

【讨论】:

  • 确保在没有任何非空行的情况下处理到达 eof
  • @Grinnz 添加了if。这应该可以工作,因为它在 EOF 处返回一个空字符串。
  • 连接所有将被写入字符串的行。然后关闭 infile 并将字符串写回原始文件。
  • @user1424739 原文件的就地编辑是什么意思?
  • @AMC 他的意思是他想替换文件而不是创建一个新文件。
【解决方案3】:

跳过前导空行的简单过滤器

#!/usr/bin/perl

use strict;
use warnings;
use feature 'say';

my $begin = 1;

while( <> ) {
        next if /^$/ and $begin;
        $begin = 0;
        say;
}

一个班轮版本perl -0777 -pe 's/^\n+//' filename

【讨论】:

    【解决方案4】:

    这是我想出来的,我相信它仍然可以改进一点。

    with open('../resources/temp_in.txt', 'r+') as file:
        overwrite = False
        for line in file:
            if line:
                overwrite = True
                first_line = line
                break
        if overwrite:
            contents = first_line + file.read()
            file.seek(0)
            file.write(contents)
            file.truncate()
    

    这是另一种解决方案,它打开文件两次。

    with open('../resources/temp_in.txt') as file:
        for line in file:
            if line.strip():
                contents = line + file.read()
                break
        else:
            contents = ''
    
    with open('../resources/temp_in.txt', 'w') as file:
        file.write(contents)
    

    【讨论】:

    • 什么时候使用 seek 更好?什么时候关闭文件再重新打开比较好?
    • @user1424739 什么时候使用 seek 更好? 而不是什么? 什么时候关闭文件再重新打开比较好?这取决于,关闭和重新打开如何适应其余的潜在解决方案?
    • 解决方法可以是打开文件,将内容读入变量,关闭文件,去掉变量中的前导换行符,再次打开文件,将变量内容保存到文件中关闭它。这与您当前的解决方案性能有何不同。换句话说,寻找或关闭文件并重新打开它更快?
    • @user1424739 嗯,我想这是个好问题,因为我实际上是在读/写整个文件,所以应该不会有太大的不同。我会想出一个快速的解决方案。
    • @user1424739 查看我的编辑。您是否有任何测试数据,以确保其完美运行?
    【解决方案5】:

    当你找到一个不只是换行符的行时设置一个标志,并在设置该标志时打印:

    awk '/./{f=1}f' file
    

    例如:

    $ printf '\n\n\nfoo\nbar\n'
    
    
    
    foo
    bar
    
    $ printf '\n\n\nfoo\nbar\n' | awk '/./{f=1}f'
    foo
    bar
    

    【讨论】:

      猜你喜欢
      • 2012-04-09
      • 1970-01-01
      • 1970-01-01
      • 2020-11-10
      • 2021-02-24
      • 2015-11-22
      • 1970-01-01
      • 1970-01-01
      • 2018-05-12
      相关资源
      最近更新 更多