I have two questions regarding Ruby.
For the below code#1, I am trying to print all the file names inside a folder, but "puts text" will gave me "/folder1/folder2/filename1.txt" for example. How can I just print just "filename1" without the directory and the .txt
number1:
Dir.glob('/folder1/folder2/*.txt').each do |text|
puts text
number2: i am trying to combine two array
a = [16,5,6,8,7]
b = [people,men,guys,boys,you]
the output will look like:
people:16, men:5, guys:6, boys:8, you:7
i converted a to string by using .to_s but i still can't combine them.
You want File.basename:
Dir.glob('/folder1/folder2/*.txt').each do |path|
puts File.basename(path, '.txt')
end
Related
I have a text file like this:
User accounts for \\AGGREP-1
-------------------------------------------------------------------------------
Administrator users grzesieklocal
Guest scom SUPPORT_8855
The command completed successfully.
First line is empty line. I want to delete every empty lines in this file and every line containing words "User accounts for", "-------", "The command". I want to have only lines containing users. I don't want to delete only first 4 and the last one lines, because it can be more users in some systems and file will contain more lines.
I load file using
a = IO.readlines("test.txt")
Is any way to delete lines containing specific words?
Solution
This structure reads the file line by line, and write a new file directly :
def unwanted?(line)
line.strip.empty? ||
line.include?('User accounts') ||
line.include?('-------------') ||
line.include?('The command completed')
end
File.open('just_users.txt', 'w+') do |out|
File.foreach('test.txt') do |line|
out.puts line unless unwanted?(line)
end
end
If you're familiar with regexp, you could use :
def unwanted?(line)
line =~ /^(User accounts|------------|The command completed|\s*$)/
end
Warning from your code
The message warning: string literal in condition appears when you try to use :
string = "nothing"
if string.include? "a" or "b"
puts "FOUND!"
end
It outputs :
parse_text.rb:16: warning: string literal in condition
FOUND!
Because it should be written :
string = 'nothing'
if string.include?('a') || string.include?('b')
puts "FOUND!"
end
See this question for more info.
IO::readlines returns an array, so you could use Array#select to select just the lines you need. Bear in mind that this means that your whole input file will be in memory, which might be a problem, if the file is really large.
An alternative approach would be to use IO::foreach, which processes one line at a time:
selected_lines = []
IO.foreach('test.txt') { |line| selected_lines << line if line_matches_your_requirements }
Have a txt file with the following:
Anders Hansen;87442355;11;87
Jens Hansen;22338843;23;11
Nanna Kvist;25233255;24;84
I would like to search the file after a specific name taken from the user input. Then save that line into an array, splittet via ";". Can't get it to work though. This is my code:
user1 = []
puts "Start by entering the full name of user 1: "
input = gets.chomp
File.open("userregister.txt") do |f|
f.each_line { |line|
if line =~ input then do |line|
user1 << line.split(';').map
=~ in ruby tries to match a string with a regex (or vice versa). Here, you use it with two strings, which gives an error:
'foo' =~ 'bar' # => TypeError: type mismatch: String given
There are more appropriate String methods to use instead. In your case, #start_with? does the job. If you wanted to check if the latter is contained somewhere as a substring (but not necessary the beginning), you can use #include?.
In case you actually wanted to take a regex as a user input (generally a bad idea), you can convert it from string to regex:
line =~ /#{input}/
Looking at the file format, I would actually use Ruby CSV class. By specifying the column separator to ;, you will get an array for each row.
require 'csv'
input = gets.chomp
CSV.foreach('userregister.txt', col_sep: ';') do |row|
if row[0].downcase == input.downcase
# Do stuffs with row[1..-1]
end
end
I'm trying to take input from the user, search through a text file (case insensitively), and then display the match from the file if it matches (with the case of the word in the file). I don't know how to get the word from the file, here's my code:
found = 0
words = []
puts "Please enter a word to add to text file"
input = gets.chomp
#Open text file in read mode
File.open("filename", "r+") do |f|
f.each do |line|
if line.match(/\b#{input}\b/i)
puts "#{input} was found in the file." # <--- I want to show the matched word here
#Set to 1 indicating word was found
found = 1
end
end
end
So, what you want to do is to store the result of the match method, you can then get the actual matched word out of that, ie.
if m = line.match( /\b#{input}\b/i )
puts "#{m[0]} was found in the file."
# ... etc.
end
Update
Btw, you didn't ask - but I would use scan in this case, so that I got an array of the matched words on each line (for when there's more than one match on the same line), something like this:
if m = line.scan( /\b#{input}\b/i )
puts "Matches found on line #{f.lineno}: #{m.join(', ')}"
# ... etc.
end
If you don't need to report the locations of the matches and the file is not overly large, you could just do this:
File.read("testfile").scan /\b#{input}\b/i
Let's try it:
text = <<THE_END
Now is the time for all good people
to come to the aid of their local
grocers, because grocers are important
to our well-being. One more thing.
Grocers sell ice cream, and boy do I
love ice cream.
THE_END
input = "grocers"
F_NAME = "text"
File.write(F_NAME, text)
File.read(F_NAME).scan /\b#{input}\b/i
# => ["grocers", "grocers", "Grocers"]
File.read(F_NAME) returns the entire text file in a single string. scan /\b#{input}\b/i is sent to that string.
I have a script that telnets into a box, runs a command, and saves the output. I run another script after that which parses through the output file, comparing it to key words that are located in another file for matching. If a line is matched, it should save the entire line (from the original telnet-output) to a new file.
Here is the portion of the script that deals with parsing text:
def parse_file
filter = []
temp_file = File.open('C:\Ruby193\scripts\PARSED_TRIAL.txt', 'a+')
t = File.open('C:\Ruby193\scripts\TRIAL_output_log.txt')
filter = File.open('C:\Ruby193\scripts\Filtered_text.txt').readlines
t.each do |line|
filter.each do |segment|
if (line =~ /#{segment}/)
temp_file.puts line
end
end
end
t.close()
temp_file.close()
end
Currently, it is only saving the last run string located in array filter and saving that to temp_file. It looks like the loop does not run all the strings in the array, or does not save them all. I have five strings placed inside the text file Filtered_text.txt. It only prints my last matched line into temp_file.
This (untested code) will duplicate the original code, only more succinctly and idiomatically:
filter = Regexp.union(File.open('C:\Ruby193\scripts\Filtered_text.txt').readlines.map(&:chomp))
File.open('C:\Ruby193\scripts\PARSED_TRIAL.txt', 'a+') do |temp_file|
File.foreach('C:\Ruby193\scripts\TRIAL_output_log.txt') do |l|
temp_file.puts l if (l[filter])
end
end
To give you an idea what is happening:
Regexp.union(%w[a b c])
=> /a|b|c/
This gives you a regular expression that'll walk through the string looking for any substring matches. It's a case-sensitive search.
If you want to close those holes, use something like:
Regexp.new(
'\b' + Regexp.union(
File.open('C:\Ruby193\scripts\Filtered_text.txt').readlines.map(&:chomp)
).source + '\b',
Regexp::IGNORECASE
)
which, using the same sample input array as above would result in:
/\ba|b|c\b/i
I'm trying to write my first Ruby script that will rename files in a specific folder. I am basing my script off of this response : How to rename a file in Ruby?. However, I need help elaborating on some things. Here is the code from the above link that I currently have written out.
puts "Renaming files..."
folder_path = "/Desktop/untitled/"
Dir.glob( folder_path + "*" ).sort.each do |f|
filename = File.basename(f, File.extname(f))
File.rename( f, folder_path + filename.capitalize + File.extname(f))
end
puts "Renaming complete."
With this example, I understand that the script is simply capitalizing the name of the original file. But what do I do if I want to insert a segment in the name of the file. Say for example I have:
"This is my name."
written out. What would I do if I just want to focus on the "my name" portion, and change it into something that would state:
"This is my (first) name."
Also, what if I wanted to remove a space:
"This is myfirstname."
Thanks so much!
If you want to achieve replacing portion of the filename with something else, you should use a sub or gsub function of the String class:
filename = File.basename(f, File.extname(f))
Now in filename you have stored a String representing a current file's name. You can check it using instance_of? function of an Object class, just if you're curious:
filename.instance_of?(String)
# -> true
What you should do is to use gsub method to replace all occurencies of given string, or sub to replace only first of it. Here you can find detailed information of using these functions.
I suppose in your case this should do the trick:
filename.gsub('my name', 'my (first) name')
# 2nd question:
filename.gsub("my first name", "myfirstname")
Also, regular expressions are allowed in sub and gsub methods. You should give it a try if you want to write more complex patterns, for example strip all numbers from file.
A nice way to create strings with variables in Ruby is:
first = "Eugene"
filename = "This is my #{first} name"
filename is equal to "This is my Eugene name"
so with the file portions you asked about:
"This is my #{folder_path}#{filename.gsub!(' ', '').capitalize}#{File.extname(f)}"
Removing spaces can be done with gsub
(check out string class documentation http://www.ruby-doc.org/core-1.9.3/String.html):
filename.gsub(' ', '')
You can also use the File classes join method to concatenate strings into a path and avoid cross platform issues with slashes ('/' vs '\')
For more see http://www.ruby-doc.org/core-1.9.3/File.html#method-c-join