Reputation: 8759
I have this small script which I wrote to rename variables in my JS file.
puts "Current name?"
current_name = gets.chomp
puts "New name? (Recommended usage of $ prefix)"
new_name = gets.chomp
#
File.open(file_name, 'r+') do |file|
file_content = file.read
edited_file = file_content.sub "var "+current_name+" = ", "var "+new_name+" = "
edited_file = edited_file.gsub current_name+".", new_name+"."
file.truncate(0)
file.write(edited_file)
end
When I run it, it changes all variable names and that looks just fine in my Atom text editor. But if I open this same file in Sublime text editor all characters are bunch of numbers.
Look at the screenshot (Sublime editor in front and Atom in background)
After trying this: Write and read a file with utf-8 encoding
File.open(file_name, 'r+:UTF-8') do |file|
file_content = file.read
edited_file = file_content.sub "var "+current_name+" = ", "var "+new_name+" = "
edited_file = edited_file.gsub current_name+".", new_name+"."
file.truncate(0)
file.write edited_file
end
The invalid characters still appear and valid output afterwards. Here is screenshot:
Upvotes: 1
Views: 240
Reputation: 106077
I have a hunch—but can't test it since I'm not at a computer—that File#truncate
doesn't reset the File object's internal "cursor." Since you did file.read
the cursor is at the end of the file (say, 500 bytes from the beginning). truncate
deletes everything in the file but the cursor is still at offset 500, so when you write to the file it starts writing at that position, and the preceding bytes are all set to 00
(NUL
).
When you open the file in Atom, it chooses to not display those 00
bytes. (If you can configure Atom to display invisible characters, you should. A text editor should never hide non-printable characters.) Sublime, on the other hand, sees all the 00
s and decides to display the file as a binary file in a hex view.
The fact that the first three non-zero bytes shown in Sublime are 76 61 72
—the ASCII codes for var
—would seem to support this theory.
I think the easiest solution would be to call file.rewind
before file.truncate
or file.write
:
File.open(file_name, 'r+') do |file|
file_content = file.read
file_content.sub!("var #{current_name} = ", "var #{new_name} = ")
file_content.gsub!("#{current_name}.", "#{new_name}.")
file.rewind
file.truncate(0)
file.write(file_content)
end
A better solution, perhaps, would be to embrace the prior invention of the wheel and use sed
or awk
for this.
Upvotes: 6