2012-09-22 20 views
10

Necesito analizar un archivo para obtener sentencias de SQL individuales y ejecutarlas desde el controlador de rieles.Separación de cadena sin eliminar el delimitador

tengo el siguiente código:

@sql_file = "#{RAILS_ROOT}/lib/evidence_interface_import.sql" 
@sql_stmts_array = File.read(@sql_file).split(";") 

@sql_stmts_array.each_with_index do |sql_stmt,s_index| 
    ActiveRecord::Base.connection.execute(sql_stmt) 
end 

La división elimina el ";" desde el final de los SQL. ¿Hay alguna manera de no eliminar el ";" y aún se divide usando ";".

Respuesta

3

Esto funciona (Por ejemplo select * from stuff where name = ";";.):

@sql_stmts_array = File.read(@sql_file).lines(separator=';') 
+1

La sintaxis es incorrecta para' lines (separator ='; ') '- eso funcionará pero está mal escrito. Debería ser 'lines (';')' en su lugar. Pero, en su lugar, use 'File.readlines (@sql_file, ';')' porque es más corto y logra lo mismo. –

1

Puede intentar usar scan con una expresión regular adecuada, lo que debería proporcionarle resultados similares a split, pero si desea seguir un método sin expresiones regulares, puede agregar un punto y coma a cada celda de la matriz:

@sql_stmts_array = File.read(@sql_file).split(";").each do |s| 
    s << ";" 
end 
+2

Esto tiene un efecto secundario de poner un punto y coma después de la última entrada. – willglynn

+1

¿No es eso lo que se quiere? ¿No debería haber un ';' después de cada entrada? – siame

13

Sí, scan que:

'a; b; c;'.scan(/[^;]*;/) 
#=> ["a;", " b;", " c;"] 

Usted podría deshacerse del exceso de espacio en blanco al virar en map(&:strip) después, pero probablemente no se necesita aquí.

Tenga en cuenta que esto es muy rudimentario, y algo así como una cadena literal en el SQL con un punto y coma en esto romperá esto.

+1

Una opción similar sería: ''a; segundo; c; '. scan (/.*?;/) ' – Sajjad

3

Usar una expresión regular con una búsqueda hacia atrás

split(/(?<=;)/) 
6

Al utilizar ActiveRecord::Base.connection.execute que no es necesario incluir el punto y coma en el primer lugar.

Además, otra manera de dividir sin quitar el delimitador es utilizar grupos como se muestra en el siguiente ejemplo:

"a;b;c".split(/;/) # => ["a", "b", "c"] 

"a;b;c".split(/(;)/) # => ["a", ";", "b", ";", "c"] 
+1

para muchos casos que implican tokenización y manipulación de cadenas: esta es una gran solución. –

+0

Lo marcaría como la respuesta aceptada. 'scan' parece necesitar el delimitador después de cada elemento, no solo entre ellos. –

Cuestiones relacionadas