为Ruby SQLite插入转义字符串

我正在创建一个Ruby脚本,将大约150k行的制表符分隔文本文件导入SQLite。 到目前为止:

require 'sqlite3' file = File.new("/Users/michael/catalog.txt") string = [] # Escape single quotes, remove newline, split on tabs, # wrap each item in quotes, and join with commas def prepare_for_insert(s) s.gsub(/'/,"\\\\'").chomp.split(/\t/).map {|str| "'#{str}'"}.join(", ") end file.each_line do |line| string << prepare_for_insert(line) end database = SQLite3::Database.new("/Users/michael/catalog.db") # Insert each string into the database string.each do |str| database.execute( "INSERT INTO CATALOG VALUES (#{str})") end 

尽管gsub在我的prepare_for_insert方法中转义单引号,但第一行包含单引号的脚本错误:

 /Users/michael/.rvm/gems/ruby-1.9.3-p0/gems/sqlite3-1.3.5/lib/sqlite3/database.rb:91: in `initialize': near "s": syntax error (SQLite3::SQLException) 

它在第15行出错。如果我用puts string[14]检查该行,我可以看到它在“s”附近显示错误的位置。 它看起来像这样: 'Touch the Top of the World: A Blind Man\'s Journey to Climb Farther Than the Eye Can See'

看起来单引号被转义,为什么我仍然得到错误?

不要那样做,字符串插值和SQL往往是一个糟糕的组合。 使用预准备语句,让驱动程序处理引用和转义:

 # Ditch the gsub in prepare_for_insert and... db = SQLite3::Database.new('/Users/michael/catalog.db') ins = db.prepare('insert into catalog (column_name) values (?)') string.each { |s| ins.execute(s) } 

您应该将column_name替换为实际的列名; 您不必在INSERT中指定列名,但无论如何都应该始终执行。 如果需要插入更多列,则向ins.execute添加更多占位符和参数。

使用prepareexecute应该更快,更安全,更容易,并且它不会让你觉得你在1999年编写PHP。

此外,你应该使用标准的CSV解析器来解析你的制表符分隔文件,XSV格式处理起来并不是很有趣(事实上它们是完全邪恶的)并且你有更好的时间来处理你的时间而不是处理他们的废话和边缘情况,什么不是。