【问题标题】:Replace line in text file with a new line用新行替换文本文件中的行
【发布时间】:2016-08-08 17:28:58
【问题描述】:

我想用新行替换文件中的一行,例如:

文件:

test
test
test
testing
test

来源:

def remove_line(line)
  if line == line
    #remove line including whitespace
    File.open('test.txt', 'a+') { |s| s.puts('removed successfully') }
  end
end

所以预期的输出是这样的:

remove_line('testing')
test
test
test
removed successfully
test

现在我做了一些研究,只能找到添加一个空行,我想我可以运行它并删除所有空行并附加到文件中,但必须有一种更简单的方法来用另一个字符串替换一行?

【问题讨论】:

  • 当你说if line == line 时,你想做什么?这永远是真的。
  • @Nobita 我认为他将其作为示例,如果作为参数给出的字符串等于文件中的行之一,则重写该行等。

标签: ruby file


【解决方案1】:

给定这个输入文件,存储为“test.txt”:

test
test
test
testing
test

还有这个示例代码:

def remove_line(line_to_remove)
  File.foreach("test.txt").with_index do |line, line_num|
    line.gsub!(/[\r\n]+$/, '')
    if line == line_to_remove
      puts "removed successfully"
    else
      puts line
    end
  end
end

可以成功运行:

remove_line('testing')

并得到这个输出:

test
test
test
removed successfully
test

该函数获取要删除的行的内容,并以“逐行”方式打开文件。这是惯用的 Ruby,应该优先于“slurping”文件,如对此SO question 的接受答案中所述。

一旦我们有了一条线,就需要从它中去除行尾。由于我们不确切知道它将在哪个平台上运行(或者文本文件是在哪个平台上创建的),我们使用正则表达式来查找所有已知的行结束字符('\r\n' 是 Windows,'\n'是 Linux/Unix/Mac OS X,'\r' 是 Mac Classic)。

然后我们检查该行是否与我们要删除的内容匹配。如果匹配,我们从输出中省略它,而是打印它已“成功删除”;否则,我们输出不匹配的行。

这符合最初的设计意图,但是,还有很多事情要做来改进设计并让整体功能更有用。那么为什么不继续这样做呢?

首先,我们将让函数将文件名作为参数。这将从foreach 调用中删除硬编码的"test.txt" 文件名。这将使这种变化发生:

def remove_line(filename, line_to_remove)
  File.foreach(filename).with_index do |line, line_num|
    line.gsub!(/[\r\n]+$/, '')
    if line == line_to_remove
      puts "removed successfully"
    else
      puts line
    end
  end
end

您可以通过这种方式成功运行它,它会产生完全相同的输出:

remove_line("test.txt", "testing")

接下来,让我们更改输出的发生方式,我们将使用一个块来执行此操作,因为这就是 Ruby 方式。下面是函数在输出块时的样子:

def remove_line(filename, line_to_remove, &block)
  proc = block_given? ? block : lambda {|s| puts s }
  File.foreach(filename).with_index do |line, line_num|
    line.gsub!(/[\r\n]+$/, '')
    if line == line_to_remove
      proc.call "removed successfully"
    else
      proc.call line
    end
  end
end

这是使用可选的块参数构建的,因此您可以像以前的版本一样调用它以使其工作方式完全相同,或者您可以使用显式块调用它并做一些很酷的事情。这个运行它的示例在调用puts 打印该行之前稍微修改了字符串:

remove_line("test.txt", "testing") {|s| puts "#{s} in your pants" }

再加上一点幼稚,你会得到这样的输出:

test in your pants
test in your pants
test in your pants
removed successfully in your pants
test in your pants

你现在有能力做有趣的事情,从其他有趣的事情开始。明智地使用它并继续使用 Ruby 方式。

【讨论】:

    【解决方案2】:

    首先,打开文件并保存实际内容。然后,替换字符串并将完整内容写回文件。

    def remove_line(string)
      # save the content of the file
      file = File.read('test.txt')
      # replace (globally) the search string with the new string
      new_content = file.gsub(string, 'removed succesfully')
      # open the file again and write the new content to it
      File.open('test.txt', 'w') { |line| line.puts new_content }
    end
    

    或者,而不是全局替换:

    def remove_line(string)
      file = File.read('test.txt')
      new_content = file.split("\n")
      new_content = new_content.map { |word| word == string ? 'removed succesfully' : word }.join("\n")
      File.open('test.txt', 'w') { |line| line.puts new_content }
    end
    

    【讨论】:

    • 这会覆盖整个文件
    • 它将您需要的内容写入文件。您可以尝试使用File.seek,这不会重写整个文件,但您需要将字符串替换为另一个大小完全相同的字符串。
    • 编辑了第二种方法,因为我已经离开了全局替换字符串的语句。
    • @user3097405 你不想追加到文件,而不是写入文件吗?
    • @13aal,我不确定我是否理解你的问题。只能读取写入(追加?)到一个文件,对吧?
    【解决方案3】:

    我找到了一个参考答案here 它并不完全相同,因为他们正在寻找一种模式。

    所以我会这样做:

    def remove_line(line)
      file.open('test.txt', 'a+').each_line do |line|
        line.gsub('<line/to/replace>', '<new/line/here>')
      end
    end
    

    这应该将作为参数给出的那一行替换为您想要替换的任何新行..

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-05-15
      • 1970-01-01
      • 2013-01-10
      • 1970-01-01
      • 2018-11-24
      • 1970-01-01
      • 2012-03-19
      • 2017-06-06
      相关资源
      最近更新 更多