使用ruby使用regex替换csv中的字符串

使用ruby使用regex替换csv中的字符串,ruby,string,csv,Ruby,String,Csv,我有一个csv文件,其中有一个列test和id,值为: "abc is 123 test", 1 "abc is 123 test", 2 "abc is 123 test", 3 "abc is 123 test", 4 "abc is 123 test", 5 我想用“abc is 567 test”替换“abc is 123 test” 注意:值123和567是动态值,随着每个新csv123的更改,但字符串“abc是测试”始终保持不变 我试过的代码: folder_path =

我有一个csv文件,其中有一个列test和id,值为:

"abc is 123 test", 1

"abc is 123 test", 2

"abc is 123 test", 3

"abc is 123 test", 4

"abc is 123 test", 5
我想用
“abc is 567 test”
替换
“abc is 123 test”

注意:值
123
567
是动态值,随着每个新csv
123
的更改,但字符串
“abc是测试”
始终保持不变

我试过的代码:

folder_path = "/home/test/files/"
f1 = folder_path + "abc.csv"
string_replace = "abc is 567 test"

file = IO.read(/home/test/files/abc.csv")
file_final = expected_file.gsub!("abc is".*, string_replace)
File.open(f1, 'w') { |f| f.write(file_final) }
我得到一个错误:

ArgumentError:调用
*
的参数数目错误(0表示1)


有人能帮忙吗?

虽然从技术上讲,这些文件是CSV文件,但我们可以将CSV文件视为文本,因为它们就是文本。这样,当它们很简单时,就更容易咀嚼它们

首先,我要说:

File.open('csv.new', 'w') do |fo|
  DATA.each_line do |li|
    fo.puts li.sub('123', '456')
  end
end

__END__
"abc is 123 test", 1
"abc is 123 test", 2
"abc is 123 test", 3
"abc is 123 test", 4
"abc is 123 test", 5
运行它会生成一个名为“csv.new”的文件,其中包含:

"abc is 456 test", 1
"abc is 456 test", 2
"abc is 456 test", 3
"abc is 456 test", 4
"abc is 456 test", 5
而不是:

DATA.each_line do |li|
您希望使用以下方法打开原始文件:

File.foreach("/home/test/files/abc.csv") do |li|
DATA
是访问存储在Ruby脚本末尾的示例数据的一种方法。)

'123'
容易出现误报,并且会更改子字符串:

'0123456'.sub('123', '456') # => "0456456"
为了解决这个问题,如果有子字符串匹配的可能,您应该使用更智能的搜索字符串;我会使用正则表达式:

'0123456'.sub(/\b123\b/, '456') # => "0123456"
它现在检查是否有一个单词边界围绕着
123

'0 123 456'.sub(/\b123\b/, '456') # => "0 456 456"
由于“123”可能会发生变化,因此将其指定为一个常数,然后将其替换为模式是有意义的:

TARGET_STR = '123'

'0123456'.sub(/\b#{TARGET_STR}\b/, '456') # => "0123456"
'0 123 456'.sub(/\b#{TARGET_STR}\b/, '456') # => "0 456 456"
因为我使用的块带有
open
foreach
,所以Ruby会在块结束后自动关闭文件,从而使代码更干净,并更好地管理文件句柄

您的代码:

file = IO.read(/home/test/files/abc.csv")
file_final = expected_file.gsub!("abc is".*, string_replace)
File.open(f1, 'w') { |f| f.write(file_final) }
…真是…一团糟

  • read
    对于您知道的文件大小始终小于1MB的文件来说是非常好的选择。如果您不知道这一点,特别是如果您工作在文件可以很好地进入GB范围的生产环境中,使用逐行IO会更快、更安全,因为它可以避免可伸缩性问题。有关详细信息,请参阅“”
  • 我们不知道
    expected\u file
    是什么,但它会导致错误,因为它未定义,所以Ruby会反抗,因为您对nil值使用了
    gsub!
    方法
  • 如果
    expected\u file
    是一个字符串,
    expected\u file.gsub!
    将变异
    expected\u file
    ,但将结果分配给
    file\u final
    会浪费CPU。相反,请重新使用
    expected\u file
    ,或者更好地使用:

    file_final = expected_file.gsub(
    
  • “abc is”。*
    是一个无效参数。可能
    “abc is.*”
    会更接近,但似乎您正在寻找正则表达式
    /abc is.*/
    ,但这对于更改字符串来说不是必需的,
    /123/
    '123'
    就足够了

  • gsub
    在这里也会有些过分,因为您只需要一次更换,所以
    sub
    会更快
  • 技术上

    File.open(f1, 'w') { |f| f.write(file_final) }
    
    将工作,但它更容易写为

    File.write(f1, file_final)
    

您可以将代码简化为:

File.write(
  'file.csv.new',
  File.read('file.csv').gsub(/\b123\b/, '456')
)
出于悖谬,可以写为:

File.write('file.csv.new', File.read('file.csv').gsub(/\b123\b/, '456'))

速度不会提高,反而会降低可读性。

它可以大于3位,也可以小于3位。“abc is 123测试”中的数字是多少“始终是三位数?使用
读取
和正则表达式是个坏主意,除非您总是知道文件很容易放入内存。与使用逐行IO相比,任何超过2MB的内存都会降低代码的速度。