1

I have file called regional.txt and it has data as below :

shell.SetMyFile "Ranger" 
shell.SetMyErrorFile "Discovery"
shell.SetMyFileEnabled 1 
shell.SetMyLogFileEnabled 1

Now I am reading this file using ruby and trying to filter the text from "shell.SetMyFile" and "shell.SetMyErrorFile" as Ranger and Discovery:

File.readlines("regional.txt").each do |line|
      value1 = line.split(" ")[1] if line.include?("shell.SetMyFile")
      value2 = line.split(" ")[1] if line.include?("shell.SetMyErrorFile ")
      puts value1, value2
end

My result is 1 ,1 rather than Ranger and Discovery. This is because include? method considering the "shell.SetMyFileEnabled" and "shell.SetMyLogFileEnabled". How can I filter it to the desired result ?

cyborg
  • 870
  • 1
  • 15
  • 34

2 Answers2

2

A quick fix would be as follows:

# Need to declare the variables outside the block,
# so they are not trapped in that scope
value1 = nil
value2 = nil

File.readlines("regional.txt").each do |line|
  # NOTE: added trailing space here:
  if line.include?("shell.SetMyFile ")
    value1 = line.split(" ")[1] 
  end
  if line.include?("shell.SetMyErrorFile ")
    value2 = line.split(" ")[1] 
  end
end

puts value1, value2
# => "Ranger"
# => "Discovery"

You could do it with regex as well:

key_vals = File.
  read("regional.txt").
  scan(/\w+\.(\w+)[^\w]+(\w+)/).
  to_h

value1 = key_vals["SetMyFile"]
# => "Ranger"

value2 = key_vals["SetMyErrorFile"]
# => "Discovery"

To explain the regex, consider shell.SetMyFile "Ranger":

  • \w+: any number of alphaneumeric chars, matches the prefix e.g. shell
  • \.: a literal period
  • (\w+): match group 1, any number of alphaneumeric chars, matches the suffix e.g. SetMyFile
  • [^\w]+ any number of non-alphaneumeric chars, matches whitespace as well as quotation
  • (\w+) match group 2, any number of alphaneumeric chars. matches the value string e.g. Ranger

After calling scan you are left with a nested array:

File.read("regional.txt").scan(/\w+\.(\w+) \"?(\w+)/)
# => [
#   ["SetMyFile", "Ranger"],
#   ["SetMyErrorFile", "Discovery"], 
#   ["SetMyFileEnabled", "1"],
#   ["SetMyLogFileEnabled", "1"]
# ]

You can call to_h on this to turn it into a hash, for easy lookup by key:

max pleaner
  • 26,189
  • 9
  • 66
  • 118
0

Let's create your file.

FName = "regional.txt"

File.write FName, <<~END
shell.SetMyFile "Ranger" 
shell.SetMyErrorFile "Discovery"
shell.SetMyFileEnabled 1 
shell.SetMyLogFileEnabled 1
END
  #=> 113

We are given:

desired_lines = ["shell.SetMyFile", "shell.SetMyErrorFile"]

I understand you wish to print certain information from the file. In general it's preferable to extract the desired information into a Ruby object then print the information of interest. That way, if you wish to manipulate the resulting object in your code you will not have to change that part of the code.

One could read the lines of the file into an array, select the elements of interest then extract the information of interest. It's more efficient, however, to read the file line-by-line and save the information of interest from those lines that begin with an element of desired_lines, which requires only a single pass through the file and avoids the need to construct an intermediate array. You can do that with the methods IO::foreach and Enumerator#with_object:

a = IO.foreach(FName).with_object([]) do |line,arr|
  label, value = line.chomp.delete('"').split
  arr << value if desired_lines.include?(label)
end
  #=> ["Ranger", "Discovery"] 

Alternatively, if you wish tie "Ranger" and "Discovery" to their corresponding lines, you could substitute:

arr << [label, value]

for

arr << value

in which case the return value would be:

[["shell.SetMyFile", "Ranger"], ["shell.SetMyErrorFile", "Discovery"]] 
Cary Swoveland
  • 106,649
  • 6
  • 63
  • 100