ruby 如何在文本文件中插入字符串

6tdlim6h  于 2023-11-18  发布在  Ruby
关注(0)|答案(6)|浏览(112)

我有一个配置文件,我想添加一个字符串,看起来像这样:

line1
line2
line3
line4

字符串
新的字符串不应该被追加,而是写在文件中间的某个地方。因此,我在文件中寻找一个特定的位置(或字符串),当它被找到时,我插入我的新字符串:

file = File.open(path,"r+")
while (!file.eof?)
  line = file.readline
  if (line.downcase.starts_with?("line1"))
    file.write("Some nice little sentence")
  end
end


问题是Ruby用新文本覆盖了该位置的行,因此结果如下:

line1
Some nice little sentence
line3
line4


我想要的是“真实的”插入:

line1
Some nice little sentence
line2
line3
line4


如何才能做到这一点?

mec1mxoz

mec1mxoz1#

如果它是一个小文件,我认为最简单的方法是:

  • 阅读完整的文件。
  • 插入管路。
  • 写入新文件。

这就是Rails在幕后的工作方式。
或者你可以一行一行地复制它,然后像这样用mv覆盖原始文件:

require 'fileutils'

tempfile=File.open("file.tmp", 'w')
f=File.new("file.txt")
f.each do |line|
  tempfile<<line
  if line.downcase=~/^line2/
    tempfile << "Some nice little sentence\n"
  end
end
f.close
tempfile.close

FileUtils.mv("file.tmp", "file.txt")

字符串

ibrsph3r

ibrsph3r2#

def replace(filepath, regexp, *args, &block)
  content = File.read(filepath).gsub(regexp, *args, &block)
  File.open(filepath, 'wb') { |file| file.write(content) }
end

replace(my_file, /^line2/mi) { |match| "Some nice little sentence"}

line1
Some nice little sentence
line2
line3
line4

字符串
如果你想添加到现有的...

replace(my_file, /^line2/mi) do |match| 
  "#{match} Some nice little sentence"
end

line1
line2 Some nice little sentence
line2
line3
line4

w9apscun

w9apscun3#

还有几个选择:

file = File.read(path).sub(/line2\n/, 'Some nice little sentence\n\1')
File.write(path, file)

file = File.readlines(path)
index = file.index("line2")
file.insert(index, "Some nice little sentence")
File.write(path, file)

字符串

ej83mcc0

ej83mcc04#

最简单的方法是读取内存中的整个文件,然后将第一部分写回文件,将插入的行写回文件,并将剩余部分写回文件。当您将文件作为行数组读取时,这应该相对简单,但如果文件非常大,则可能会遇到问题,因为您必须使用这种方法将整个文件读取到内存中。
或者,你可以找到你想要插入行的位置,将该位置之后的行读入内存,在文件中查找该位置,将新的行写入文件,最后将剩余的行写入文件。如果文件的剩余部分非常大,你也会遇到问题,因为你必须将其全部读入内存。
第三种方法是将第一部分写入一个新文件,将插入的行写入一个新文件,将原始文件的其余部分写入新文件,最后在文件系统中用新文件替换旧文件。这种方法允许您每次处理一行,因此可以处理内存不适合的文件。
文件写入工作方式是这样的,因为文件就像一个固定大小的字节数组:当你写一个字节到文件你将覆盖现有的字节(我忽略了你在这里附加到文件的情况)因此,将任何内容插入文件的唯一方法是首先通过从旧位置阅读旧内容并将其写入新位置来将旧内容移动到新位置。您可以将数据“插入”到现在的空闲区域中。

8mmmxcuj

8mmmxcuj5#

tty-file gem有一个inject_into_file方法用于此目的。
安装gem:

gem install tty-file

字符串
然后:

require 'tty-file'
TTY::File.inject_into_file("filename.rb", "Some nice little sentence", after: "line1\n")

piok6c0g

piok6c0g6#

受到@Jonas Elfström提供的答案的启发,我写了一个Ruby gem,名为insert_after,你可以从命令行或Ruby程序中使用它。

命令行用法

# Inserts 'Inserted 1' after the first line containing 'line' into demo/my_file.txt:
$ insert_after line 'Inserted 1' demo/my_file.txt

# Inserts 'Inserted 1' after every line containing 'line' into demo/my_file.txt:
$ insert_after -a line 'Inserted 1' demo/my_file.txt

# Inserts an empty line after the first line containing 'line 1' into demo/my_file.txt:
$ insert_after 'line 1' '' demo/my_file.txt

# Inserts an empty line after every line containing 'line 1' into demo/my_file.txt:
$ insert_after -a 'line 1' '' demo/my_file.txt

# Inserts 'Inserted 2' after the first line starting with 'line 2' into demo/my_file.txt:
$ insert_after '^line 2' 'Inserted 2' demo/my_file.txt

# Inserts 'Inserted 2' after every line starting with 'line 2' into demo/my_file.txt:
$ insert_after -a '^line 2' 'Inserted 2' demo/my_file.txt

# Inserts 'Inserted 3' after the first line containing an 'e' followed by a '2' into demo/my_file.txt:
$ insert_after 'e.*2' 'Inserted 3' demo/my_file.txt

# Inserts 'Inserted 3' after every line containing an 'e' followed by a '2' into demo/my_file.txt:
$ insert_after -a 'e.*2' 'Inserted 3' demo/my_file.txt

字符串

Ruby程序使用

require 'insert_after'

InsertAfer.insert_after 'line 2', 'New line', 'my_file.txt'
InsertAfter.insert_after 'line',   'Another line from Ruby', 'my_file.txt', all: true

程序代码

这是主要的方法:

def self.insert_after(regex, new_line, filename, all: false)
  InsertAfter.help "#{filename} does not exist" unless File.exist? filename

  original_file  = File.new(filename)
  temporary_file = Tempfile.new(filename)
  inserted = false
  begin
    original_file.each do |line|
      temporary_file << line
      if line.downcase.match?(/#{regex}/)
        temporary_file << "#{new_line}\n" unless inserted
        inserted = true unless all
      end
    end
    original_file.close
    temporary_file.close
    FileUtils.mv(temporary_file.path, filename)
  ensure
    original_file.close unless original_file.closed?
    temporary_file.close unless temporary_file.closed?
    temporary_file.unlink if File.exist? temporary_file.path
  end
end

命令行安装

$ gem install insert_after

安装用于Ruby程序

将这一行添加到应用程序的Gemfile中:

gem 'insert_after'


.或将以下内容添加到应用程序的.gemspec

spec.add_dependency 'insert_after'


然后执行:

$ bundle

更多信息

参见https://github.com/mslinn/insert_after

相关问题