如何在模式文本中搜索模式并将其替换为给定值

时间:2009-08-13 21:14:06

标签: ruby file-io

我正在寻找一个脚本来搜索模式的文件(或文件列表),如果找到,则用给定的值替换该模式。

思想?

11 个答案:

答案 0 :(得分:181)

这是一个快速的简短方法。

file_names = ['foo.txt', 'bar.txt']

file_names.each do |file_name|
  text = File.read(file_name)
  new_contents = text.gsub(/search_regexp/, "replacement string")

  # To merely print the contents of the file, use:
  puts new_contents

  # To write changes to the file, use:
  File.open(file_name, "w") {|file| file.puts new_contents }
end

答案 1 :(得分:97)

实际上,Ruby确实具有就地编辑功能。像Perl一样,你可以说

ruby -pi.bak -e "gsub(/oldtext/, 'newtext')" *.txt

这会将双引号中的代码应用于当前目录中名称以“.txt”结尾的所有文件。编辑文件的备份副本将以“.bak”扩展名创建(我认为“foobar.txt.bak”)。

注意:这似乎不适用于多行搜索。对于那些,你必须用另一个不那么漂亮的方式来做,在正则表达式周围有一个包装脚本。

答案 2 :(得分:40)

答案 3 :(得分:11)

实际上没有一种方法可以就地编辑文件。当你可以逃脱它时通常做的事情(即文件不是太大)是,你将文件读入内存(File.read),对读取字符串执行替换(String#gsub )然后将更改后的字符串写回文件(File.openFile#write)。

如果文件大到不可行,你需要做的就是以块的形式读取文件(如果要替换的模式不会跨越多行,那么一个块通常意味着一行 - 你可以使用File.foreach逐行读取文件,并为每个块执行替换并将其附加到临时文件。完成对源文件的迭代后,关闭它并使用FileUtils.mv用临时文件覆盖它。

答案 4 :(得分:8)

另一种方法是在Ruby中使用inplace编辑(而不是从命令行):

#!/usr/bin/ruby

def inplace_edit(file, bak, &block)
    old_stdout = $stdout
    argf = ARGF.clone

    argf.argv.replace [file]
    argf.inplace_mode = bak
    argf.each_line do |line|
        yield line
    end
    argf.close

    $stdout = old_stdout
end

inplace_edit 'test.txt', '.bak' do |line|
    line = line.gsub(/search1/,"replace1")
    line = line.gsub(/search2/,"replace2")
    print line unless line.match(/something/)
end

如果您不想创建备份,请将“.bak”更改为“”。

答案 5 :(得分:6)

这对我有用:

filename = "foo"
text = File.read(filename) 
content = text.gsub(/search_regexp/, "replacestring")
File.open(filename, "w") { |file| file << content }

答案 6 :(得分:6)

这是在给定目录的所有文件中查找/替换的解决方案。基本上我接受了sepp2k提供的答案并扩展了它。

# First set the files to search/replace in
files = Dir.glob("/PATH/*")

# Then set the variables for find/replace
@original_string_or_regex = /REGEX/
@replacement_string = "STRING"

files.each do |file_name|
  text = File.read(file_name)
  replace = text.gsub!(@original_string_or_regex, @replacement_string)
  File.open(file_name, "w") { |file| file.puts replace }
end

答案 7 :(得分:4)

require 'trollop'

opts = Trollop::options do
  opt :output, "Output file", :type => String
  opt :input, "Input file", :type => String
  opt :ss, "String to search", :type => String
  opt :rs, "String to replace", :type => String
end

text = File.read(opts.input)
text.gsub!(opts.ss, opts.rs)
File.open(opts.output, 'w') { |f| f.write(text) }

答案 8 :(得分:1)

如果您需要跨行边界进行替换,那么使用ruby -pi -e将无法正常工作,因为p一次处理一行。相反,我推荐以下内容,尽管它可能会因多GB文件而失败:

ruby -e "file='translation.ja.yml'; IO.write(file, (IO.read(file).gsub(/\s+'$/, %q('))))"

正在寻找引号后面的空格(可能包括新行),在这种情况下,它会删除空格。 %q(')只是引用引号字符的一种奇特方式。

答案 9 :(得分:0)

这里是jim的一个衬里的替代品,这次是在剧本中

async

将其保存在脚本中,例如replace.rb

使用

从命令行开始
ARGV[0..-3].each{|f| File.write(f, File.read(f).gsub(ARGV[-2],ARGV[-1]))}

* .txt可以替换为其他选择或某些文件名或路径

细分,以便我可以解释发生了什么,但仍然可执行

replace.rb *.txt <string_to_replace> <replacement>

答案 10 :(得分:0)

我正在使用 tty-file gem

除了替换之外,它还包括追加、前置(在文件内的给定文本/正则表达式上)、差异等。