How to parse a string into a hash table in RubyWhat is the difference between String and string in C#?How do I iterate over the words of a string?How do I read / convert an InputStream into a String in Java?How do I parse a string to a float or int in Python?How to write a switch statement in RubyHow do I make the first letter of a string uppercase in JavaScript?How to replace all occurrences of a string in JavaScriptHow to check whether a string contains a substring in JavaScript?Does Python have a string 'contains' substring method?How do I convert a String to an int in Java?
Jesus' words on the Jews
Extracting sublists that contain similar elements
Why does my circuit work on a breadboard, but not on a perfboard? I am new to soldering
Earliest use of "rookie"?
Smallest Guaranteed hash collision cycle length
What kind of SATA connector is this?
What's the difference between "за ... от" and "в ... от"?
Centering subcaptions in a tikz pgfplot subfigure environment?
Developers demotivated due to working on same project for more than 2 years
On studying Computer Science vs. Software Engineering to become a proficient coder
Rounding a number extracted by jq to limit the decimal points
What's tha name for when you write multiple voices on same staff? And are there any cons?
Can someone explain homicide-related death rates?
Why was Endgame Thanos so different than Infinity War Thanos?
Unexpected Netflix account registered to my Gmail address - any way it could be a hack attempt?
In books, how many dragons are there in present time?
Ito`s Lemma problem
Why is it harder to turn a motor/generator with shorted terminals?
What to do if SUS scores contradict qualitative feedback?
Why are solar panels kept tilted?
Anabelian geometry ~ higher category theory
Jumping frame contents with beamer and pgfplots
Can a tourist shoot a gun in the USA?
Is Germany still exporting arms to countries involved in Yemen?
How to parse a string into a hash table in Ruby
What is the difference between String and string in C#?How do I iterate over the words of a string?How do I read / convert an InputStream into a String in Java?How do I parse a string to a float or int in Python?How to write a switch statement in RubyHow do I make the first letter of a string uppercase in JavaScript?How to replace all occurrences of a string in JavaScriptHow to check whether a string contains a substring in JavaScript?Does Python have a string 'contains' substring method?How do I convert a String to an int in Java?
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty height:90px;width:728px;box-sizing:border-box;
I am getting data as a string from a remote device. I need to parse the data. The data usually come like this:
MO SCGR SC RSITE ALARM_SITUATION
RXOTG-59 59 0 EK0322 ABIS PATH FAULT
RXOCF-59 EK0322 LOCAL MODE
RXOTRX-59-0 4 EK0322 LOCAL MODE
RXOTRX-59-1 EK0322 LOCAL MODE
RXOTRX-59-4 0 EK0322 LOCAL MODE
RXOTRX-59-5 1 3 EK0322 LOCAL MODE
RXOTRX-59-8 EK0322 LOCAL MODE
RXOTRX-59-9 EK0322 LOCAL MODE
I will love to have the data as an array of arrays or any other programmatically sensible structure.
I am splitting the data into an array using:
str.split("rn")
and then removing the extra space on each element in the array with:
tsgs.map! tsg
but this has limitation in that the empty cells are not considered. I expect the array to contain five elements, but it instead contains less than five.
Case 1: In this case, I get the expected result:
RXOTG-59 59 0 EK0322 ABIS PATH FAULT
converts to
["RXOTG-59", "59", "0", "EK0322", "ABIS PATH FAULT"]
Case 2: In this case, I get an unexpected result:
RXOTRX-59-9 EK0322 LOCAL MODE
converts to
["RXOTRX-59-9", "EK0322", "LOCAL MODE"]
def getCommandResult(tgdatas)
tgdatas_arr = tgdatas.split("rn")
tsgs = tgdatas_arr[5..tgdatas_arr.index("END")-2]
tsgs.map! tsg
return tsgs
end
ruby string parsing hashtable
add a comment |
I am getting data as a string from a remote device. I need to parse the data. The data usually come like this:
MO SCGR SC RSITE ALARM_SITUATION
RXOTG-59 59 0 EK0322 ABIS PATH FAULT
RXOCF-59 EK0322 LOCAL MODE
RXOTRX-59-0 4 EK0322 LOCAL MODE
RXOTRX-59-1 EK0322 LOCAL MODE
RXOTRX-59-4 0 EK0322 LOCAL MODE
RXOTRX-59-5 1 3 EK0322 LOCAL MODE
RXOTRX-59-8 EK0322 LOCAL MODE
RXOTRX-59-9 EK0322 LOCAL MODE
I will love to have the data as an array of arrays or any other programmatically sensible structure.
I am splitting the data into an array using:
str.split("rn")
and then removing the extra space on each element in the array with:
tsgs.map! tsg
but this has limitation in that the empty cells are not considered. I expect the array to contain five elements, but it instead contains less than five.
Case 1: In this case, I get the expected result:
RXOTG-59 59 0 EK0322 ABIS PATH FAULT
converts to
["RXOTG-59", "59", "0", "EK0322", "ABIS PATH FAULT"]
Case 2: In this case, I get an unexpected result:
RXOTRX-59-9 EK0322 LOCAL MODE
converts to
["RXOTRX-59-9", "EK0322", "LOCAL MODE"]
def getCommandResult(tgdatas)
tgdatas_arr = tgdatas.split("rn")
tsgs = tgdatas_arr[5..tgdatas_arr.index("END")-2]
tsgs.map! tsg
return tsgs
end
ruby string parsing hashtable
add a comment |
I am getting data as a string from a remote device. I need to parse the data. The data usually come like this:
MO SCGR SC RSITE ALARM_SITUATION
RXOTG-59 59 0 EK0322 ABIS PATH FAULT
RXOCF-59 EK0322 LOCAL MODE
RXOTRX-59-0 4 EK0322 LOCAL MODE
RXOTRX-59-1 EK0322 LOCAL MODE
RXOTRX-59-4 0 EK0322 LOCAL MODE
RXOTRX-59-5 1 3 EK0322 LOCAL MODE
RXOTRX-59-8 EK0322 LOCAL MODE
RXOTRX-59-9 EK0322 LOCAL MODE
I will love to have the data as an array of arrays or any other programmatically sensible structure.
I am splitting the data into an array using:
str.split("rn")
and then removing the extra space on each element in the array with:
tsgs.map! tsg
but this has limitation in that the empty cells are not considered. I expect the array to contain five elements, but it instead contains less than five.
Case 1: In this case, I get the expected result:
RXOTG-59 59 0 EK0322 ABIS PATH FAULT
converts to
["RXOTG-59", "59", "0", "EK0322", "ABIS PATH FAULT"]
Case 2: In this case, I get an unexpected result:
RXOTRX-59-9 EK0322 LOCAL MODE
converts to
["RXOTRX-59-9", "EK0322", "LOCAL MODE"]
def getCommandResult(tgdatas)
tgdatas_arr = tgdatas.split("rn")
tsgs = tgdatas_arr[5..tgdatas_arr.index("END")-2]
tsgs.map! tsg
return tsgs
end
ruby string parsing hashtable
I am getting data as a string from a remote device. I need to parse the data. The data usually come like this:
MO SCGR SC RSITE ALARM_SITUATION
RXOTG-59 59 0 EK0322 ABIS PATH FAULT
RXOCF-59 EK0322 LOCAL MODE
RXOTRX-59-0 4 EK0322 LOCAL MODE
RXOTRX-59-1 EK0322 LOCAL MODE
RXOTRX-59-4 0 EK0322 LOCAL MODE
RXOTRX-59-5 1 3 EK0322 LOCAL MODE
RXOTRX-59-8 EK0322 LOCAL MODE
RXOTRX-59-9 EK0322 LOCAL MODE
I will love to have the data as an array of arrays or any other programmatically sensible structure.
I am splitting the data into an array using:
str.split("rn")
and then removing the extra space on each element in the array with:
tsgs.map! tsg
but this has limitation in that the empty cells are not considered. I expect the array to contain five elements, but it instead contains less than five.
Case 1: In this case, I get the expected result:
RXOTG-59 59 0 EK0322 ABIS PATH FAULT
converts to
["RXOTG-59", "59", "0", "EK0322", "ABIS PATH FAULT"]
Case 2: In this case, I get an unexpected result:
RXOTRX-59-9 EK0322 LOCAL MODE
converts to
["RXOTRX-59-9", "EK0322", "LOCAL MODE"]
def getCommandResult(tgdatas)
tgdatas_arr = tgdatas.split("rn")
tsgs = tgdatas_arr[5..tgdatas_arr.index("END")-2]
tsgs.map! tsg
return tsgs
end
ruby string parsing hashtable
ruby string parsing hashtable
edited Mar 24 at 15:45
sawa
134k31211309
134k31211309
asked Mar 23 at 13:01
Emmanuel AmoduEmmanuel Amodu
86111
86111
add a comment |
add a comment |
3 Answers
3
active
oldest
votes
Your string1, modified slightly:
data = <<END
MO SCGR SC RSITE ALARM_SITUATION
RXOTG-59 59 0 EK0322 ABIS PATH FAULT
RXOCF-59 EK0322 LOCAL MODE
RXOTRX-59-0 4 EK0322 LOCAL MODE
RXOTRX-59-1 EK0322 LOCAL MODE
RXOTRX-59-4 0
RXOTRX-59-5 1 3 EK0322 LOCAL MODE
RXOTRX-59-8 EK0322 LOCAL MODE
RXOTRX-59-9 EK0322 LOCAL MODE
END
This string looks very much like CSV data structure, so we might be tempted to convert it to a CSV string, thereby allowing us to bring to bear the methods provided by the CSV class.
Convert string to CSV string
Code
def convert_to_csv(data)
cols = data[/.+?n/].gsub(/ S/).map Regexp.last_match.begin(0)
data.each_line.map do |s|
cols.each
s.gsub(/ *, */, ',')
end.join
end
Convert string
Now convert the string data
to a CSV string.
csv_data = convert_to_csv(data)
puts csv_data
MO,SCGR,SC,RSITE,ALARM_SITUATION
RXOTG-59,59,0,EK0322,ABIS PATH FAULT
RXOCF-59,,,EK0322,LOCAL MODE
RXOTRX-59-0,4,,EK0322,LOCAL MODE
RXOTRX-59-1,,,EK0322,LOCAL MODE
RXOTRX-59-4,,0
RXOTRX-59-5,1,3,EK0322,LOCAL MODE
RXOTRX-59-8,,,EK0322,LOCAL MODE
RXOTRX-59-9,,,EK0322,LOCAL MODE
Explanation
The steps are as follows.
s = data[/.+?n/]
#=> "MO SCGR SC RSITE ALARM_SITUATIONn"
e0 = s.gsub(/ S/)
#=> #<Enumerator: "MO ... ALARM_SITUATIONn":gsub(/ S/)>
cols = e0.map Regexp.last_match.begin(0) - 1
#=> [17, 23, 34, 50]
e1 = data.each_line
#=> #<Enumerator: "MO ... LOCAL MODEn":each_line>
a = e1.map do |s|
cols.each
s.gsub(/ *, */,',')
end
#=> ["MO,SCGR,SC,RSITE,ALARM_SITUATIONn",
# "RXOTG-59,59,0,EK0322,ABIS PATH FAULTn",
# ...
# "RXOTRX-59-9,,,EK0322,LOCAL MODEn"]
a.join
#=> < return value above >
Let's have a closer look at the calculation of a
. First, the block variable s
is assigned to the first element generated by the enumerator e1
:
s = e1.next
#=> "MO SCGR SC RSITE ALARM_SITUATIONn"
The block calculation is then performed:
cols.each
s #=> "MO ,SCGR ,SC ,RSITE ,ALARM_SITUATIONn"
s.gsub(/ *, */,',')
#=> "MO,SCGR,SC,RSITE,ALARM_SITUATIONn"
The regular expression used with gsub
reads, "match zero or more spaces followed by a comma, followed by zero or more spaces".
When the short line is passed to the block the following calculation is performed.
s = "RXOTRX-59-4 0"
s.size
#=> 25
cols
#=> [17, 23, 34, 50]
cols.each
s #=> "RXOTRX-59-4 , ,0"
s.gsub(/ *, */,',')
#=> "RXOTRX-59-4,,0"
The remaining elements of e1
are processed similarly.
Convert the CSV string to a hash
We may now make use of CSV methods. For example, suppose we wish to create an array of hashes whose keys are the header elements, downcased and converted to symbols and values of "SCGR"
and "SC"
are to be converted to integers. To do that we make use of the class method CSV::new, specifying appropriate values for method options.
Construct the hash
require 'csv'
CSV.new(csv_data, headers: true, header_converters: :symbol,
converters: :all).to_a.map(&:to_h)
#=> [:mo=>"RXOTG-59", :scgr=>59, :sc=>0, :rsite=>"EK0322",
# :alarm_situation=>"ABIS PATH FAULT",
# :mo=>"RXOCF-59", :scgr=>nil, :sc=>nil, :rsite=>"EK0322",
# :alarm_situation=>"LOCAL MODE",
# :mo=>"RXOTRX-59-0", :scgr=>4, :sc=>nil, :rsite=>"EK0322",
# :alarm_situation=>"LOCAL MODE",
# :mo=>"RXOTRX-59-1", :scgr=>nil, :sc=>nil, :rsite=>"EK0322",
# :alarm_situation=>"LOCAL MODE",
# :mo=>"RXOTRX-59-4", :scgr=>nil, :sc=>0, :rsite=>nil,
# :alarm_situation=>nil,
# :mo=>"RXOTRX-59-5", :scgr=>1, :sc=>3, :rsite=>nil"EK0322",
# :alarm_situation=>"LOCAL MODE",
# :mo=>"RXOTRX-59-8", :scgr=>nil, :sc=>nil, :rsite=>"EK0322",
# :alarm_situation=>"LOCAL MODE",
# :mo=>"RXOTRX-59-9", :scgr=>nil, :sc=>nil, :rsite=>"EK0322",
# :alarm_situation=>"LOCAL MODE"]
Explanation
The steps are as follows.
csv = CSV.new(csv_data, headers: true, header_converters: :symbol,
converters: :all)
#=> <#CSV io_type:StringIO encoding:UTF-8 lineno:0 col_sep:",
# " row_sep:"n" quote_char:""" headers:true>
a = csv.to_a
#=> [#<CSV::Row mo:"RXOTG-59" scgr:59 sc:0 rsite:"EK0322" alarm_situation:"ABIS PATH FAULT">,
# #<CSV::Row mo:"RXOCF-59" scgr:nil sc:nil rsite:"EK0322" alarm_situation:"LOCAL MODE">,
# ...
# #<CSV::Row mo:"RXOTRX-59-9" scgr:nil sc:nil rsite:"EK0322" alarm_situation:"LOCAL MODE">]
a.map(&:to_h)
#=> < hash shown above >
1 To run the code you will need to un-indent this heredoc (or change the first line to data = <<-END.lines.map(&:lstrip).join
).
1
Note that @iGian had the same idea of converting the string to a CSV string in his earlier answer.
– Cary Swoveland
Mar 23 at 22:44
I noticed that convert_to_csv method has no return statement, is there a reason for that?
– Emmanuel Amodu
Mar 24 at 7:17
1
One could writereturn data.each_line.map do |s| ... end.join
, but the keywordreturn
is redundant becausedata.each_line.map do |s| ... end.join
is the last expression evaluated in the method. Its return value is therefore the return value for the method.
– Cary Swoveland
Mar 24 at 8:14
Hi, I noticed one more thing, when the ALARM_SITUATION field is empty, I mean without even empty space it does not run check this link, rextester.com/YAB84581
– Emmanuel Amodu
Mar 24 at 18:49
Emmanuel, thanks for the heads-up. I fixed that and changed the example slightly to illustrate the issue.
– Cary Swoveland
Mar 25 at 22:52
|
show 1 more comment
String.unpack with directive "A" is nice for fixed width strings.
str = "RXOTRX-59-9 EK0322 LOCAL MODE"
p str.unpack("A20A4A11A16A15" ) # => ["RXOTRX-59-9", "", "", "EK0322", "LOCAL MODE"]
That's good to know, very useful. I noticed that if the length of the string is less than20+4+11+16+15
,unpack
effectively pads the string with spaces to make it the indicated length before executing the directive (a convenience).
– Cary Swoveland
Mar 25 at 23:12
add a comment |
Try if this can be viable for you, given the data_string
:
data_string = "MO SCGR SC RSITE ALARM_SITUATIONnRXOTG-59 59 0 EK0322 ABIS PATH FAULTnRXOCF-59 EK0322 LOCAL MODEnRXOTRX-59-0 4 EK0322 LOCAL MODEnRXOTRX-59-1 EK0322 LOCAL MODEnRXOTRX-59-4 0 EK0322 LOCAL MODEnRXOTRX-59-5 1 3 EK0322 LOCAL MODEnRXOTRX-59-8 EK0322 LOCAL MODEnRXOTRX-59-9 EK0322 LOCAL MODE"
Set the starting point of each line, since it seems to be aligned with the header.
data = data_string.split("n")
starts = [0, 18, 24, 35, 51, (data.map(&:size)).max ]
Then map each line considering the starting points, stripping trailing spaces:
data = data.map starts.each_cons(2).map a,b
So you'll end up with this array:
# [["MO", "SCGR", "SC", "RSITE", "ALARM_SITUATION"]
# ["RXOTG-59", "59", "0", "EK0322", "ABIS PATH FAULT"]
# ["RXOCF-59", "", "", "EK0322", "LOCAL MODE"]
# ["RXOTRX-59-0", "4", "", "EK0322", "LOCAL MODE"]
# ["RXOTRX-59-1", "", "", "EK0322", "LOCAL MODE"]
# ["RXOTRX-59-4", "", "0", "EK0322", "LOCAL MODE"]
# ["RXOTRX-59-5", "1", "3", "EK0322", "LOCAL MODE"]
# ["RXOTRX-59-8", "", "", "EK0322", "LOCAL MODE"]
# ["RXOTRX-59-9", "", "", "EK0322", "LOCAL MODE"]]
You can then convert it to a hash or use the csv library to manipulate your data.
Here is a way to generate an array of hashes:
headers = data[0]
body = data[1..]
body.map headers.map(&:to_sym).zip(line).to_h
#=> [:MO=>"RXOTG-59", :SCGR=>"59", :SC=>"0", :RSITE=>"EK0322", :ALARM_SITUATION=>"ABIS PATH FAULT", :MO=>"RXOCF-59", :SCGR=>"", :SC=>"", :RSITE=>"EK0322", :ALARM_SITUATION=>"LOCAL MODE", ...
It would be better if you can get the indices instarts
automatically using the header information. See that each column name does not include a space? Also, the complicated code to get the last index is unnecessary. You can have0
there.
– sawa
Mar 24 at 15:54
1
@sawa, thank you for pointing that0
works anyway as last starting point. I did not added automation for finding the starting points because being not comfortable with regexp I came up with an ugly:data[0].each_char.each_cons(2).with_index.with_object([]) res << i + 1 if (a == ' ' && b != ' ')
. So, I decided to pass over.
– iGian
Mar 24 at 20:02
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55313981%2fhow-to-parse-a-string-into-a-hash-table-in-ruby%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
Your string1, modified slightly:
data = <<END
MO SCGR SC RSITE ALARM_SITUATION
RXOTG-59 59 0 EK0322 ABIS PATH FAULT
RXOCF-59 EK0322 LOCAL MODE
RXOTRX-59-0 4 EK0322 LOCAL MODE
RXOTRX-59-1 EK0322 LOCAL MODE
RXOTRX-59-4 0
RXOTRX-59-5 1 3 EK0322 LOCAL MODE
RXOTRX-59-8 EK0322 LOCAL MODE
RXOTRX-59-9 EK0322 LOCAL MODE
END
This string looks very much like CSV data structure, so we might be tempted to convert it to a CSV string, thereby allowing us to bring to bear the methods provided by the CSV class.
Convert string to CSV string
Code
def convert_to_csv(data)
cols = data[/.+?n/].gsub(/ S/).map Regexp.last_match.begin(0)
data.each_line.map do |s|
cols.each
s.gsub(/ *, */, ',')
end.join
end
Convert string
Now convert the string data
to a CSV string.
csv_data = convert_to_csv(data)
puts csv_data
MO,SCGR,SC,RSITE,ALARM_SITUATION
RXOTG-59,59,0,EK0322,ABIS PATH FAULT
RXOCF-59,,,EK0322,LOCAL MODE
RXOTRX-59-0,4,,EK0322,LOCAL MODE
RXOTRX-59-1,,,EK0322,LOCAL MODE
RXOTRX-59-4,,0
RXOTRX-59-5,1,3,EK0322,LOCAL MODE
RXOTRX-59-8,,,EK0322,LOCAL MODE
RXOTRX-59-9,,,EK0322,LOCAL MODE
Explanation
The steps are as follows.
s = data[/.+?n/]
#=> "MO SCGR SC RSITE ALARM_SITUATIONn"
e0 = s.gsub(/ S/)
#=> #<Enumerator: "MO ... ALARM_SITUATIONn":gsub(/ S/)>
cols = e0.map Regexp.last_match.begin(0) - 1
#=> [17, 23, 34, 50]
e1 = data.each_line
#=> #<Enumerator: "MO ... LOCAL MODEn":each_line>
a = e1.map do |s|
cols.each
s.gsub(/ *, */,',')
end
#=> ["MO,SCGR,SC,RSITE,ALARM_SITUATIONn",
# "RXOTG-59,59,0,EK0322,ABIS PATH FAULTn",
# ...
# "RXOTRX-59-9,,,EK0322,LOCAL MODEn"]
a.join
#=> < return value above >
Let's have a closer look at the calculation of a
. First, the block variable s
is assigned to the first element generated by the enumerator e1
:
s = e1.next
#=> "MO SCGR SC RSITE ALARM_SITUATIONn"
The block calculation is then performed:
cols.each
s #=> "MO ,SCGR ,SC ,RSITE ,ALARM_SITUATIONn"
s.gsub(/ *, */,',')
#=> "MO,SCGR,SC,RSITE,ALARM_SITUATIONn"
The regular expression used with gsub
reads, "match zero or more spaces followed by a comma, followed by zero or more spaces".
When the short line is passed to the block the following calculation is performed.
s = "RXOTRX-59-4 0"
s.size
#=> 25
cols
#=> [17, 23, 34, 50]
cols.each
s #=> "RXOTRX-59-4 , ,0"
s.gsub(/ *, */,',')
#=> "RXOTRX-59-4,,0"
The remaining elements of e1
are processed similarly.
Convert the CSV string to a hash
We may now make use of CSV methods. For example, suppose we wish to create an array of hashes whose keys are the header elements, downcased and converted to symbols and values of "SCGR"
and "SC"
are to be converted to integers. To do that we make use of the class method CSV::new, specifying appropriate values for method options.
Construct the hash
require 'csv'
CSV.new(csv_data, headers: true, header_converters: :symbol,
converters: :all).to_a.map(&:to_h)
#=> [:mo=>"RXOTG-59", :scgr=>59, :sc=>0, :rsite=>"EK0322",
# :alarm_situation=>"ABIS PATH FAULT",
# :mo=>"RXOCF-59", :scgr=>nil, :sc=>nil, :rsite=>"EK0322",
# :alarm_situation=>"LOCAL MODE",
# :mo=>"RXOTRX-59-0", :scgr=>4, :sc=>nil, :rsite=>"EK0322",
# :alarm_situation=>"LOCAL MODE",
# :mo=>"RXOTRX-59-1", :scgr=>nil, :sc=>nil, :rsite=>"EK0322",
# :alarm_situation=>"LOCAL MODE",
# :mo=>"RXOTRX-59-4", :scgr=>nil, :sc=>0, :rsite=>nil,
# :alarm_situation=>nil,
# :mo=>"RXOTRX-59-5", :scgr=>1, :sc=>3, :rsite=>nil"EK0322",
# :alarm_situation=>"LOCAL MODE",
# :mo=>"RXOTRX-59-8", :scgr=>nil, :sc=>nil, :rsite=>"EK0322",
# :alarm_situation=>"LOCAL MODE",
# :mo=>"RXOTRX-59-9", :scgr=>nil, :sc=>nil, :rsite=>"EK0322",
# :alarm_situation=>"LOCAL MODE"]
Explanation
The steps are as follows.
csv = CSV.new(csv_data, headers: true, header_converters: :symbol,
converters: :all)
#=> <#CSV io_type:StringIO encoding:UTF-8 lineno:0 col_sep:",
# " row_sep:"n" quote_char:""" headers:true>
a = csv.to_a
#=> [#<CSV::Row mo:"RXOTG-59" scgr:59 sc:0 rsite:"EK0322" alarm_situation:"ABIS PATH FAULT">,
# #<CSV::Row mo:"RXOCF-59" scgr:nil sc:nil rsite:"EK0322" alarm_situation:"LOCAL MODE">,
# ...
# #<CSV::Row mo:"RXOTRX-59-9" scgr:nil sc:nil rsite:"EK0322" alarm_situation:"LOCAL MODE">]
a.map(&:to_h)
#=> < hash shown above >
1 To run the code you will need to un-indent this heredoc (or change the first line to data = <<-END.lines.map(&:lstrip).join
).
1
Note that @iGian had the same idea of converting the string to a CSV string in his earlier answer.
– Cary Swoveland
Mar 23 at 22:44
I noticed that convert_to_csv method has no return statement, is there a reason for that?
– Emmanuel Amodu
Mar 24 at 7:17
1
One could writereturn data.each_line.map do |s| ... end.join
, but the keywordreturn
is redundant becausedata.each_line.map do |s| ... end.join
is the last expression evaluated in the method. Its return value is therefore the return value for the method.
– Cary Swoveland
Mar 24 at 8:14
Hi, I noticed one more thing, when the ALARM_SITUATION field is empty, I mean without even empty space it does not run check this link, rextester.com/YAB84581
– Emmanuel Amodu
Mar 24 at 18:49
Emmanuel, thanks for the heads-up. I fixed that and changed the example slightly to illustrate the issue.
– Cary Swoveland
Mar 25 at 22:52
|
show 1 more comment
Your string1, modified slightly:
data = <<END
MO SCGR SC RSITE ALARM_SITUATION
RXOTG-59 59 0 EK0322 ABIS PATH FAULT
RXOCF-59 EK0322 LOCAL MODE
RXOTRX-59-0 4 EK0322 LOCAL MODE
RXOTRX-59-1 EK0322 LOCAL MODE
RXOTRX-59-4 0
RXOTRX-59-5 1 3 EK0322 LOCAL MODE
RXOTRX-59-8 EK0322 LOCAL MODE
RXOTRX-59-9 EK0322 LOCAL MODE
END
This string looks very much like CSV data structure, so we might be tempted to convert it to a CSV string, thereby allowing us to bring to bear the methods provided by the CSV class.
Convert string to CSV string
Code
def convert_to_csv(data)
cols = data[/.+?n/].gsub(/ S/).map Regexp.last_match.begin(0)
data.each_line.map do |s|
cols.each
s.gsub(/ *, */, ',')
end.join
end
Convert string
Now convert the string data
to a CSV string.
csv_data = convert_to_csv(data)
puts csv_data
MO,SCGR,SC,RSITE,ALARM_SITUATION
RXOTG-59,59,0,EK0322,ABIS PATH FAULT
RXOCF-59,,,EK0322,LOCAL MODE
RXOTRX-59-0,4,,EK0322,LOCAL MODE
RXOTRX-59-1,,,EK0322,LOCAL MODE
RXOTRX-59-4,,0
RXOTRX-59-5,1,3,EK0322,LOCAL MODE
RXOTRX-59-8,,,EK0322,LOCAL MODE
RXOTRX-59-9,,,EK0322,LOCAL MODE
Explanation
The steps are as follows.
s = data[/.+?n/]
#=> "MO SCGR SC RSITE ALARM_SITUATIONn"
e0 = s.gsub(/ S/)
#=> #<Enumerator: "MO ... ALARM_SITUATIONn":gsub(/ S/)>
cols = e0.map Regexp.last_match.begin(0) - 1
#=> [17, 23, 34, 50]
e1 = data.each_line
#=> #<Enumerator: "MO ... LOCAL MODEn":each_line>
a = e1.map do |s|
cols.each
s.gsub(/ *, */,',')
end
#=> ["MO,SCGR,SC,RSITE,ALARM_SITUATIONn",
# "RXOTG-59,59,0,EK0322,ABIS PATH FAULTn",
# ...
# "RXOTRX-59-9,,,EK0322,LOCAL MODEn"]
a.join
#=> < return value above >
Let's have a closer look at the calculation of a
. First, the block variable s
is assigned to the first element generated by the enumerator e1
:
s = e1.next
#=> "MO SCGR SC RSITE ALARM_SITUATIONn"
The block calculation is then performed:
cols.each
s #=> "MO ,SCGR ,SC ,RSITE ,ALARM_SITUATIONn"
s.gsub(/ *, */,',')
#=> "MO,SCGR,SC,RSITE,ALARM_SITUATIONn"
The regular expression used with gsub
reads, "match zero or more spaces followed by a comma, followed by zero or more spaces".
When the short line is passed to the block the following calculation is performed.
s = "RXOTRX-59-4 0"
s.size
#=> 25
cols
#=> [17, 23, 34, 50]
cols.each
s #=> "RXOTRX-59-4 , ,0"
s.gsub(/ *, */,',')
#=> "RXOTRX-59-4,,0"
The remaining elements of e1
are processed similarly.
Convert the CSV string to a hash
We may now make use of CSV methods. For example, suppose we wish to create an array of hashes whose keys are the header elements, downcased and converted to symbols and values of "SCGR"
and "SC"
are to be converted to integers. To do that we make use of the class method CSV::new, specifying appropriate values for method options.
Construct the hash
require 'csv'
CSV.new(csv_data, headers: true, header_converters: :symbol,
converters: :all).to_a.map(&:to_h)
#=> [:mo=>"RXOTG-59", :scgr=>59, :sc=>0, :rsite=>"EK0322",
# :alarm_situation=>"ABIS PATH FAULT",
# :mo=>"RXOCF-59", :scgr=>nil, :sc=>nil, :rsite=>"EK0322",
# :alarm_situation=>"LOCAL MODE",
# :mo=>"RXOTRX-59-0", :scgr=>4, :sc=>nil, :rsite=>"EK0322",
# :alarm_situation=>"LOCAL MODE",
# :mo=>"RXOTRX-59-1", :scgr=>nil, :sc=>nil, :rsite=>"EK0322",
# :alarm_situation=>"LOCAL MODE",
# :mo=>"RXOTRX-59-4", :scgr=>nil, :sc=>0, :rsite=>nil,
# :alarm_situation=>nil,
# :mo=>"RXOTRX-59-5", :scgr=>1, :sc=>3, :rsite=>nil"EK0322",
# :alarm_situation=>"LOCAL MODE",
# :mo=>"RXOTRX-59-8", :scgr=>nil, :sc=>nil, :rsite=>"EK0322",
# :alarm_situation=>"LOCAL MODE",
# :mo=>"RXOTRX-59-9", :scgr=>nil, :sc=>nil, :rsite=>"EK0322",
# :alarm_situation=>"LOCAL MODE"]
Explanation
The steps are as follows.
csv = CSV.new(csv_data, headers: true, header_converters: :symbol,
converters: :all)
#=> <#CSV io_type:StringIO encoding:UTF-8 lineno:0 col_sep:",
# " row_sep:"n" quote_char:""" headers:true>
a = csv.to_a
#=> [#<CSV::Row mo:"RXOTG-59" scgr:59 sc:0 rsite:"EK0322" alarm_situation:"ABIS PATH FAULT">,
# #<CSV::Row mo:"RXOCF-59" scgr:nil sc:nil rsite:"EK0322" alarm_situation:"LOCAL MODE">,
# ...
# #<CSV::Row mo:"RXOTRX-59-9" scgr:nil sc:nil rsite:"EK0322" alarm_situation:"LOCAL MODE">]
a.map(&:to_h)
#=> < hash shown above >
1 To run the code you will need to un-indent this heredoc (or change the first line to data = <<-END.lines.map(&:lstrip).join
).
1
Note that @iGian had the same idea of converting the string to a CSV string in his earlier answer.
– Cary Swoveland
Mar 23 at 22:44
I noticed that convert_to_csv method has no return statement, is there a reason for that?
– Emmanuel Amodu
Mar 24 at 7:17
1
One could writereturn data.each_line.map do |s| ... end.join
, but the keywordreturn
is redundant becausedata.each_line.map do |s| ... end.join
is the last expression evaluated in the method. Its return value is therefore the return value for the method.
– Cary Swoveland
Mar 24 at 8:14
Hi, I noticed one more thing, when the ALARM_SITUATION field is empty, I mean without even empty space it does not run check this link, rextester.com/YAB84581
– Emmanuel Amodu
Mar 24 at 18:49
Emmanuel, thanks for the heads-up. I fixed that and changed the example slightly to illustrate the issue.
– Cary Swoveland
Mar 25 at 22:52
|
show 1 more comment
Your string1, modified slightly:
data = <<END
MO SCGR SC RSITE ALARM_SITUATION
RXOTG-59 59 0 EK0322 ABIS PATH FAULT
RXOCF-59 EK0322 LOCAL MODE
RXOTRX-59-0 4 EK0322 LOCAL MODE
RXOTRX-59-1 EK0322 LOCAL MODE
RXOTRX-59-4 0
RXOTRX-59-5 1 3 EK0322 LOCAL MODE
RXOTRX-59-8 EK0322 LOCAL MODE
RXOTRX-59-9 EK0322 LOCAL MODE
END
This string looks very much like CSV data structure, so we might be tempted to convert it to a CSV string, thereby allowing us to bring to bear the methods provided by the CSV class.
Convert string to CSV string
Code
def convert_to_csv(data)
cols = data[/.+?n/].gsub(/ S/).map Regexp.last_match.begin(0)
data.each_line.map do |s|
cols.each
s.gsub(/ *, */, ',')
end.join
end
Convert string
Now convert the string data
to a CSV string.
csv_data = convert_to_csv(data)
puts csv_data
MO,SCGR,SC,RSITE,ALARM_SITUATION
RXOTG-59,59,0,EK0322,ABIS PATH FAULT
RXOCF-59,,,EK0322,LOCAL MODE
RXOTRX-59-0,4,,EK0322,LOCAL MODE
RXOTRX-59-1,,,EK0322,LOCAL MODE
RXOTRX-59-4,,0
RXOTRX-59-5,1,3,EK0322,LOCAL MODE
RXOTRX-59-8,,,EK0322,LOCAL MODE
RXOTRX-59-9,,,EK0322,LOCAL MODE
Explanation
The steps are as follows.
s = data[/.+?n/]
#=> "MO SCGR SC RSITE ALARM_SITUATIONn"
e0 = s.gsub(/ S/)
#=> #<Enumerator: "MO ... ALARM_SITUATIONn":gsub(/ S/)>
cols = e0.map Regexp.last_match.begin(0) - 1
#=> [17, 23, 34, 50]
e1 = data.each_line
#=> #<Enumerator: "MO ... LOCAL MODEn":each_line>
a = e1.map do |s|
cols.each
s.gsub(/ *, */,',')
end
#=> ["MO,SCGR,SC,RSITE,ALARM_SITUATIONn",
# "RXOTG-59,59,0,EK0322,ABIS PATH FAULTn",
# ...
# "RXOTRX-59-9,,,EK0322,LOCAL MODEn"]
a.join
#=> < return value above >
Let's have a closer look at the calculation of a
. First, the block variable s
is assigned to the first element generated by the enumerator e1
:
s = e1.next
#=> "MO SCGR SC RSITE ALARM_SITUATIONn"
The block calculation is then performed:
cols.each
s #=> "MO ,SCGR ,SC ,RSITE ,ALARM_SITUATIONn"
s.gsub(/ *, */,',')
#=> "MO,SCGR,SC,RSITE,ALARM_SITUATIONn"
The regular expression used with gsub
reads, "match zero or more spaces followed by a comma, followed by zero or more spaces".
When the short line is passed to the block the following calculation is performed.
s = "RXOTRX-59-4 0"
s.size
#=> 25
cols
#=> [17, 23, 34, 50]
cols.each
s #=> "RXOTRX-59-4 , ,0"
s.gsub(/ *, */,',')
#=> "RXOTRX-59-4,,0"
The remaining elements of e1
are processed similarly.
Convert the CSV string to a hash
We may now make use of CSV methods. For example, suppose we wish to create an array of hashes whose keys are the header elements, downcased and converted to symbols and values of "SCGR"
and "SC"
are to be converted to integers. To do that we make use of the class method CSV::new, specifying appropriate values for method options.
Construct the hash
require 'csv'
CSV.new(csv_data, headers: true, header_converters: :symbol,
converters: :all).to_a.map(&:to_h)
#=> [:mo=>"RXOTG-59", :scgr=>59, :sc=>0, :rsite=>"EK0322",
# :alarm_situation=>"ABIS PATH FAULT",
# :mo=>"RXOCF-59", :scgr=>nil, :sc=>nil, :rsite=>"EK0322",
# :alarm_situation=>"LOCAL MODE",
# :mo=>"RXOTRX-59-0", :scgr=>4, :sc=>nil, :rsite=>"EK0322",
# :alarm_situation=>"LOCAL MODE",
# :mo=>"RXOTRX-59-1", :scgr=>nil, :sc=>nil, :rsite=>"EK0322",
# :alarm_situation=>"LOCAL MODE",
# :mo=>"RXOTRX-59-4", :scgr=>nil, :sc=>0, :rsite=>nil,
# :alarm_situation=>nil,
# :mo=>"RXOTRX-59-5", :scgr=>1, :sc=>3, :rsite=>nil"EK0322",
# :alarm_situation=>"LOCAL MODE",
# :mo=>"RXOTRX-59-8", :scgr=>nil, :sc=>nil, :rsite=>"EK0322",
# :alarm_situation=>"LOCAL MODE",
# :mo=>"RXOTRX-59-9", :scgr=>nil, :sc=>nil, :rsite=>"EK0322",
# :alarm_situation=>"LOCAL MODE"]
Explanation
The steps are as follows.
csv = CSV.new(csv_data, headers: true, header_converters: :symbol,
converters: :all)
#=> <#CSV io_type:StringIO encoding:UTF-8 lineno:0 col_sep:",
# " row_sep:"n" quote_char:""" headers:true>
a = csv.to_a
#=> [#<CSV::Row mo:"RXOTG-59" scgr:59 sc:0 rsite:"EK0322" alarm_situation:"ABIS PATH FAULT">,
# #<CSV::Row mo:"RXOCF-59" scgr:nil sc:nil rsite:"EK0322" alarm_situation:"LOCAL MODE">,
# ...
# #<CSV::Row mo:"RXOTRX-59-9" scgr:nil sc:nil rsite:"EK0322" alarm_situation:"LOCAL MODE">]
a.map(&:to_h)
#=> < hash shown above >
1 To run the code you will need to un-indent this heredoc (or change the first line to data = <<-END.lines.map(&:lstrip).join
).
Your string1, modified slightly:
data = <<END
MO SCGR SC RSITE ALARM_SITUATION
RXOTG-59 59 0 EK0322 ABIS PATH FAULT
RXOCF-59 EK0322 LOCAL MODE
RXOTRX-59-0 4 EK0322 LOCAL MODE
RXOTRX-59-1 EK0322 LOCAL MODE
RXOTRX-59-4 0
RXOTRX-59-5 1 3 EK0322 LOCAL MODE
RXOTRX-59-8 EK0322 LOCAL MODE
RXOTRX-59-9 EK0322 LOCAL MODE
END
This string looks very much like CSV data structure, so we might be tempted to convert it to a CSV string, thereby allowing us to bring to bear the methods provided by the CSV class.
Convert string to CSV string
Code
def convert_to_csv(data)
cols = data[/.+?n/].gsub(/ S/).map Regexp.last_match.begin(0)
data.each_line.map do |s|
cols.each
s.gsub(/ *, */, ',')
end.join
end
Convert string
Now convert the string data
to a CSV string.
csv_data = convert_to_csv(data)
puts csv_data
MO,SCGR,SC,RSITE,ALARM_SITUATION
RXOTG-59,59,0,EK0322,ABIS PATH FAULT
RXOCF-59,,,EK0322,LOCAL MODE
RXOTRX-59-0,4,,EK0322,LOCAL MODE
RXOTRX-59-1,,,EK0322,LOCAL MODE
RXOTRX-59-4,,0
RXOTRX-59-5,1,3,EK0322,LOCAL MODE
RXOTRX-59-8,,,EK0322,LOCAL MODE
RXOTRX-59-9,,,EK0322,LOCAL MODE
Explanation
The steps are as follows.
s = data[/.+?n/]
#=> "MO SCGR SC RSITE ALARM_SITUATIONn"
e0 = s.gsub(/ S/)
#=> #<Enumerator: "MO ... ALARM_SITUATIONn":gsub(/ S/)>
cols = e0.map Regexp.last_match.begin(0) - 1
#=> [17, 23, 34, 50]
e1 = data.each_line
#=> #<Enumerator: "MO ... LOCAL MODEn":each_line>
a = e1.map do |s|
cols.each
s.gsub(/ *, */,',')
end
#=> ["MO,SCGR,SC,RSITE,ALARM_SITUATIONn",
# "RXOTG-59,59,0,EK0322,ABIS PATH FAULTn",
# ...
# "RXOTRX-59-9,,,EK0322,LOCAL MODEn"]
a.join
#=> < return value above >
Let's have a closer look at the calculation of a
. First, the block variable s
is assigned to the first element generated by the enumerator e1
:
s = e1.next
#=> "MO SCGR SC RSITE ALARM_SITUATIONn"
The block calculation is then performed:
cols.each
s #=> "MO ,SCGR ,SC ,RSITE ,ALARM_SITUATIONn"
s.gsub(/ *, */,',')
#=> "MO,SCGR,SC,RSITE,ALARM_SITUATIONn"
The regular expression used with gsub
reads, "match zero or more spaces followed by a comma, followed by zero or more spaces".
When the short line is passed to the block the following calculation is performed.
s = "RXOTRX-59-4 0"
s.size
#=> 25
cols
#=> [17, 23, 34, 50]
cols.each
s #=> "RXOTRX-59-4 , ,0"
s.gsub(/ *, */,',')
#=> "RXOTRX-59-4,,0"
The remaining elements of e1
are processed similarly.
Convert the CSV string to a hash
We may now make use of CSV methods. For example, suppose we wish to create an array of hashes whose keys are the header elements, downcased and converted to symbols and values of "SCGR"
and "SC"
are to be converted to integers. To do that we make use of the class method CSV::new, specifying appropriate values for method options.
Construct the hash
require 'csv'
CSV.new(csv_data, headers: true, header_converters: :symbol,
converters: :all).to_a.map(&:to_h)
#=> [:mo=>"RXOTG-59", :scgr=>59, :sc=>0, :rsite=>"EK0322",
# :alarm_situation=>"ABIS PATH FAULT",
# :mo=>"RXOCF-59", :scgr=>nil, :sc=>nil, :rsite=>"EK0322",
# :alarm_situation=>"LOCAL MODE",
# :mo=>"RXOTRX-59-0", :scgr=>4, :sc=>nil, :rsite=>"EK0322",
# :alarm_situation=>"LOCAL MODE",
# :mo=>"RXOTRX-59-1", :scgr=>nil, :sc=>nil, :rsite=>"EK0322",
# :alarm_situation=>"LOCAL MODE",
# :mo=>"RXOTRX-59-4", :scgr=>nil, :sc=>0, :rsite=>nil,
# :alarm_situation=>nil,
# :mo=>"RXOTRX-59-5", :scgr=>1, :sc=>3, :rsite=>nil"EK0322",
# :alarm_situation=>"LOCAL MODE",
# :mo=>"RXOTRX-59-8", :scgr=>nil, :sc=>nil, :rsite=>"EK0322",
# :alarm_situation=>"LOCAL MODE",
# :mo=>"RXOTRX-59-9", :scgr=>nil, :sc=>nil, :rsite=>"EK0322",
# :alarm_situation=>"LOCAL MODE"]
Explanation
The steps are as follows.
csv = CSV.new(csv_data, headers: true, header_converters: :symbol,
converters: :all)
#=> <#CSV io_type:StringIO encoding:UTF-8 lineno:0 col_sep:",
# " row_sep:"n" quote_char:""" headers:true>
a = csv.to_a
#=> [#<CSV::Row mo:"RXOTG-59" scgr:59 sc:0 rsite:"EK0322" alarm_situation:"ABIS PATH FAULT">,
# #<CSV::Row mo:"RXOCF-59" scgr:nil sc:nil rsite:"EK0322" alarm_situation:"LOCAL MODE">,
# ...
# #<CSV::Row mo:"RXOTRX-59-9" scgr:nil sc:nil rsite:"EK0322" alarm_situation:"LOCAL MODE">]
a.map(&:to_h)
#=> < hash shown above >
1 To run the code you will need to un-indent this heredoc (or change the first line to data = <<-END.lines.map(&:lstrip).join
).
edited Mar 25 at 22:51
answered Mar 23 at 22:17
Cary SwovelandCary Swoveland
72.2k54167
72.2k54167
1
Note that @iGian had the same idea of converting the string to a CSV string in his earlier answer.
– Cary Swoveland
Mar 23 at 22:44
I noticed that convert_to_csv method has no return statement, is there a reason for that?
– Emmanuel Amodu
Mar 24 at 7:17
1
One could writereturn data.each_line.map do |s| ... end.join
, but the keywordreturn
is redundant becausedata.each_line.map do |s| ... end.join
is the last expression evaluated in the method. Its return value is therefore the return value for the method.
– Cary Swoveland
Mar 24 at 8:14
Hi, I noticed one more thing, when the ALARM_SITUATION field is empty, I mean without even empty space it does not run check this link, rextester.com/YAB84581
– Emmanuel Amodu
Mar 24 at 18:49
Emmanuel, thanks for the heads-up. I fixed that and changed the example slightly to illustrate the issue.
– Cary Swoveland
Mar 25 at 22:52
|
show 1 more comment
1
Note that @iGian had the same idea of converting the string to a CSV string in his earlier answer.
– Cary Swoveland
Mar 23 at 22:44
I noticed that convert_to_csv method has no return statement, is there a reason for that?
– Emmanuel Amodu
Mar 24 at 7:17
1
One could writereturn data.each_line.map do |s| ... end.join
, but the keywordreturn
is redundant becausedata.each_line.map do |s| ... end.join
is the last expression evaluated in the method. Its return value is therefore the return value for the method.
– Cary Swoveland
Mar 24 at 8:14
Hi, I noticed one more thing, when the ALARM_SITUATION field is empty, I mean without even empty space it does not run check this link, rextester.com/YAB84581
– Emmanuel Amodu
Mar 24 at 18:49
Emmanuel, thanks for the heads-up. I fixed that and changed the example slightly to illustrate the issue.
– Cary Swoveland
Mar 25 at 22:52
1
1
Note that @iGian had the same idea of converting the string to a CSV string in his earlier answer.
– Cary Swoveland
Mar 23 at 22:44
Note that @iGian had the same idea of converting the string to a CSV string in his earlier answer.
– Cary Swoveland
Mar 23 at 22:44
I noticed that convert_to_csv method has no return statement, is there a reason for that?
– Emmanuel Amodu
Mar 24 at 7:17
I noticed that convert_to_csv method has no return statement, is there a reason for that?
– Emmanuel Amodu
Mar 24 at 7:17
1
1
One could write
return data.each_line.map do |s| ... end.join
, but the keyword return
is redundant because data.each_line.map do |s| ... end.join
is the last expression evaluated in the method. Its return value is therefore the return value for the method.– Cary Swoveland
Mar 24 at 8:14
One could write
return data.each_line.map do |s| ... end.join
, but the keyword return
is redundant because data.each_line.map do |s| ... end.join
is the last expression evaluated in the method. Its return value is therefore the return value for the method.– Cary Swoveland
Mar 24 at 8:14
Hi, I noticed one more thing, when the ALARM_SITUATION field is empty, I mean without even empty space it does not run check this link, rextester.com/YAB84581
– Emmanuel Amodu
Mar 24 at 18:49
Hi, I noticed one more thing, when the ALARM_SITUATION field is empty, I mean without even empty space it does not run check this link, rextester.com/YAB84581
– Emmanuel Amodu
Mar 24 at 18:49
Emmanuel, thanks for the heads-up. I fixed that and changed the example slightly to illustrate the issue.
– Cary Swoveland
Mar 25 at 22:52
Emmanuel, thanks for the heads-up. I fixed that and changed the example slightly to illustrate the issue.
– Cary Swoveland
Mar 25 at 22:52
|
show 1 more comment
String.unpack with directive "A" is nice for fixed width strings.
str = "RXOTRX-59-9 EK0322 LOCAL MODE"
p str.unpack("A20A4A11A16A15" ) # => ["RXOTRX-59-9", "", "", "EK0322", "LOCAL MODE"]
That's good to know, very useful. I noticed that if the length of the string is less than20+4+11+16+15
,unpack
effectively pads the string with spaces to make it the indicated length before executing the directive (a convenience).
– Cary Swoveland
Mar 25 at 23:12
add a comment |
String.unpack with directive "A" is nice for fixed width strings.
str = "RXOTRX-59-9 EK0322 LOCAL MODE"
p str.unpack("A20A4A11A16A15" ) # => ["RXOTRX-59-9", "", "", "EK0322", "LOCAL MODE"]
That's good to know, very useful. I noticed that if the length of the string is less than20+4+11+16+15
,unpack
effectively pads the string with spaces to make it the indicated length before executing the directive (a convenience).
– Cary Swoveland
Mar 25 at 23:12
add a comment |
String.unpack with directive "A" is nice for fixed width strings.
str = "RXOTRX-59-9 EK0322 LOCAL MODE"
p str.unpack("A20A4A11A16A15" ) # => ["RXOTRX-59-9", "", "", "EK0322", "LOCAL MODE"]
String.unpack with directive "A" is nice for fixed width strings.
str = "RXOTRX-59-9 EK0322 LOCAL MODE"
p str.unpack("A20A4A11A16A15" ) # => ["RXOTRX-59-9", "", "", "EK0322", "LOCAL MODE"]
edited Mar 23 at 15:59
answered Mar 23 at 15:33
steenslagsteenslag
64k11103143
64k11103143
That's good to know, very useful. I noticed that if the length of the string is less than20+4+11+16+15
,unpack
effectively pads the string with spaces to make it the indicated length before executing the directive (a convenience).
– Cary Swoveland
Mar 25 at 23:12
add a comment |
That's good to know, very useful. I noticed that if the length of the string is less than20+4+11+16+15
,unpack
effectively pads the string with spaces to make it the indicated length before executing the directive (a convenience).
– Cary Swoveland
Mar 25 at 23:12
That's good to know, very useful. I noticed that if the length of the string is less than
20+4+11+16+15
, unpack
effectively pads the string with spaces to make it the indicated length before executing the directive (a convenience).– Cary Swoveland
Mar 25 at 23:12
That's good to know, very useful. I noticed that if the length of the string is less than
20+4+11+16+15
, unpack
effectively pads the string with spaces to make it the indicated length before executing the directive (a convenience).– Cary Swoveland
Mar 25 at 23:12
add a comment |
Try if this can be viable for you, given the data_string
:
data_string = "MO SCGR SC RSITE ALARM_SITUATIONnRXOTG-59 59 0 EK0322 ABIS PATH FAULTnRXOCF-59 EK0322 LOCAL MODEnRXOTRX-59-0 4 EK0322 LOCAL MODEnRXOTRX-59-1 EK0322 LOCAL MODEnRXOTRX-59-4 0 EK0322 LOCAL MODEnRXOTRX-59-5 1 3 EK0322 LOCAL MODEnRXOTRX-59-8 EK0322 LOCAL MODEnRXOTRX-59-9 EK0322 LOCAL MODE"
Set the starting point of each line, since it seems to be aligned with the header.
data = data_string.split("n")
starts = [0, 18, 24, 35, 51, (data.map(&:size)).max ]
Then map each line considering the starting points, stripping trailing spaces:
data = data.map starts.each_cons(2).map a,b
So you'll end up with this array:
# [["MO", "SCGR", "SC", "RSITE", "ALARM_SITUATION"]
# ["RXOTG-59", "59", "0", "EK0322", "ABIS PATH FAULT"]
# ["RXOCF-59", "", "", "EK0322", "LOCAL MODE"]
# ["RXOTRX-59-0", "4", "", "EK0322", "LOCAL MODE"]
# ["RXOTRX-59-1", "", "", "EK0322", "LOCAL MODE"]
# ["RXOTRX-59-4", "", "0", "EK0322", "LOCAL MODE"]
# ["RXOTRX-59-5", "1", "3", "EK0322", "LOCAL MODE"]
# ["RXOTRX-59-8", "", "", "EK0322", "LOCAL MODE"]
# ["RXOTRX-59-9", "", "", "EK0322", "LOCAL MODE"]]
You can then convert it to a hash or use the csv library to manipulate your data.
Here is a way to generate an array of hashes:
headers = data[0]
body = data[1..]
body.map headers.map(&:to_sym).zip(line).to_h
#=> [:MO=>"RXOTG-59", :SCGR=>"59", :SC=>"0", :RSITE=>"EK0322", :ALARM_SITUATION=>"ABIS PATH FAULT", :MO=>"RXOCF-59", :SCGR=>"", :SC=>"", :RSITE=>"EK0322", :ALARM_SITUATION=>"LOCAL MODE", ...
It would be better if you can get the indices instarts
automatically using the header information. See that each column name does not include a space? Also, the complicated code to get the last index is unnecessary. You can have0
there.
– sawa
Mar 24 at 15:54
1
@sawa, thank you for pointing that0
works anyway as last starting point. I did not added automation for finding the starting points because being not comfortable with regexp I came up with an ugly:data[0].each_char.each_cons(2).with_index.with_object([]) res << i + 1 if (a == ' ' && b != ' ')
. So, I decided to pass over.
– iGian
Mar 24 at 20:02
add a comment |
Try if this can be viable for you, given the data_string
:
data_string = "MO SCGR SC RSITE ALARM_SITUATIONnRXOTG-59 59 0 EK0322 ABIS PATH FAULTnRXOCF-59 EK0322 LOCAL MODEnRXOTRX-59-0 4 EK0322 LOCAL MODEnRXOTRX-59-1 EK0322 LOCAL MODEnRXOTRX-59-4 0 EK0322 LOCAL MODEnRXOTRX-59-5 1 3 EK0322 LOCAL MODEnRXOTRX-59-8 EK0322 LOCAL MODEnRXOTRX-59-9 EK0322 LOCAL MODE"
Set the starting point of each line, since it seems to be aligned with the header.
data = data_string.split("n")
starts = [0, 18, 24, 35, 51, (data.map(&:size)).max ]
Then map each line considering the starting points, stripping trailing spaces:
data = data.map starts.each_cons(2).map a,b
So you'll end up with this array:
# [["MO", "SCGR", "SC", "RSITE", "ALARM_SITUATION"]
# ["RXOTG-59", "59", "0", "EK0322", "ABIS PATH FAULT"]
# ["RXOCF-59", "", "", "EK0322", "LOCAL MODE"]
# ["RXOTRX-59-0", "4", "", "EK0322", "LOCAL MODE"]
# ["RXOTRX-59-1", "", "", "EK0322", "LOCAL MODE"]
# ["RXOTRX-59-4", "", "0", "EK0322", "LOCAL MODE"]
# ["RXOTRX-59-5", "1", "3", "EK0322", "LOCAL MODE"]
# ["RXOTRX-59-8", "", "", "EK0322", "LOCAL MODE"]
# ["RXOTRX-59-9", "", "", "EK0322", "LOCAL MODE"]]
You can then convert it to a hash or use the csv library to manipulate your data.
Here is a way to generate an array of hashes:
headers = data[0]
body = data[1..]
body.map headers.map(&:to_sym).zip(line).to_h
#=> [:MO=>"RXOTG-59", :SCGR=>"59", :SC=>"0", :RSITE=>"EK0322", :ALARM_SITUATION=>"ABIS PATH FAULT", :MO=>"RXOCF-59", :SCGR=>"", :SC=>"", :RSITE=>"EK0322", :ALARM_SITUATION=>"LOCAL MODE", ...
It would be better if you can get the indices instarts
automatically using the header information. See that each column name does not include a space? Also, the complicated code to get the last index is unnecessary. You can have0
there.
– sawa
Mar 24 at 15:54
1
@sawa, thank you for pointing that0
works anyway as last starting point. I did not added automation for finding the starting points because being not comfortable with regexp I came up with an ugly:data[0].each_char.each_cons(2).with_index.with_object([]) res << i + 1 if (a == ' ' && b != ' ')
. So, I decided to pass over.
– iGian
Mar 24 at 20:02
add a comment |
Try if this can be viable for you, given the data_string
:
data_string = "MO SCGR SC RSITE ALARM_SITUATIONnRXOTG-59 59 0 EK0322 ABIS PATH FAULTnRXOCF-59 EK0322 LOCAL MODEnRXOTRX-59-0 4 EK0322 LOCAL MODEnRXOTRX-59-1 EK0322 LOCAL MODEnRXOTRX-59-4 0 EK0322 LOCAL MODEnRXOTRX-59-5 1 3 EK0322 LOCAL MODEnRXOTRX-59-8 EK0322 LOCAL MODEnRXOTRX-59-9 EK0322 LOCAL MODE"
Set the starting point of each line, since it seems to be aligned with the header.
data = data_string.split("n")
starts = [0, 18, 24, 35, 51, (data.map(&:size)).max ]
Then map each line considering the starting points, stripping trailing spaces:
data = data.map starts.each_cons(2).map a,b
So you'll end up with this array:
# [["MO", "SCGR", "SC", "RSITE", "ALARM_SITUATION"]
# ["RXOTG-59", "59", "0", "EK0322", "ABIS PATH FAULT"]
# ["RXOCF-59", "", "", "EK0322", "LOCAL MODE"]
# ["RXOTRX-59-0", "4", "", "EK0322", "LOCAL MODE"]
# ["RXOTRX-59-1", "", "", "EK0322", "LOCAL MODE"]
# ["RXOTRX-59-4", "", "0", "EK0322", "LOCAL MODE"]
# ["RXOTRX-59-5", "1", "3", "EK0322", "LOCAL MODE"]
# ["RXOTRX-59-8", "", "", "EK0322", "LOCAL MODE"]
# ["RXOTRX-59-9", "", "", "EK0322", "LOCAL MODE"]]
You can then convert it to a hash or use the csv library to manipulate your data.
Here is a way to generate an array of hashes:
headers = data[0]
body = data[1..]
body.map headers.map(&:to_sym).zip(line).to_h
#=> [:MO=>"RXOTG-59", :SCGR=>"59", :SC=>"0", :RSITE=>"EK0322", :ALARM_SITUATION=>"ABIS PATH FAULT", :MO=>"RXOCF-59", :SCGR=>"", :SC=>"", :RSITE=>"EK0322", :ALARM_SITUATION=>"LOCAL MODE", ...
Try if this can be viable for you, given the data_string
:
data_string = "MO SCGR SC RSITE ALARM_SITUATIONnRXOTG-59 59 0 EK0322 ABIS PATH FAULTnRXOCF-59 EK0322 LOCAL MODEnRXOTRX-59-0 4 EK0322 LOCAL MODEnRXOTRX-59-1 EK0322 LOCAL MODEnRXOTRX-59-4 0 EK0322 LOCAL MODEnRXOTRX-59-5 1 3 EK0322 LOCAL MODEnRXOTRX-59-8 EK0322 LOCAL MODEnRXOTRX-59-9 EK0322 LOCAL MODE"
Set the starting point of each line, since it seems to be aligned with the header.
data = data_string.split("n")
starts = [0, 18, 24, 35, 51, (data.map(&:size)).max ]
Then map each line considering the starting points, stripping trailing spaces:
data = data.map starts.each_cons(2).map a,b
So you'll end up with this array:
# [["MO", "SCGR", "SC", "RSITE", "ALARM_SITUATION"]
# ["RXOTG-59", "59", "0", "EK0322", "ABIS PATH FAULT"]
# ["RXOCF-59", "", "", "EK0322", "LOCAL MODE"]
# ["RXOTRX-59-0", "4", "", "EK0322", "LOCAL MODE"]
# ["RXOTRX-59-1", "", "", "EK0322", "LOCAL MODE"]
# ["RXOTRX-59-4", "", "0", "EK0322", "LOCAL MODE"]
# ["RXOTRX-59-5", "1", "3", "EK0322", "LOCAL MODE"]
# ["RXOTRX-59-8", "", "", "EK0322", "LOCAL MODE"]
# ["RXOTRX-59-9", "", "", "EK0322", "LOCAL MODE"]]
You can then convert it to a hash or use the csv library to manipulate your data.
Here is a way to generate an array of hashes:
headers = data[0]
body = data[1..]
body.map headers.map(&:to_sym).zip(line).to_h
#=> [:MO=>"RXOTG-59", :SCGR=>"59", :SC=>"0", :RSITE=>"EK0322", :ALARM_SITUATION=>"ABIS PATH FAULT", :MO=>"RXOCF-59", :SCGR=>"", :SC=>"", :RSITE=>"EK0322", :ALARM_SITUATION=>"LOCAL MODE", ...
edited Mar 24 at 15:56
sawa
134k31211309
134k31211309
answered Mar 23 at 14:40
iGianiGian
5,5062725
5,5062725
It would be better if you can get the indices instarts
automatically using the header information. See that each column name does not include a space? Also, the complicated code to get the last index is unnecessary. You can have0
there.
– sawa
Mar 24 at 15:54
1
@sawa, thank you for pointing that0
works anyway as last starting point. I did not added automation for finding the starting points because being not comfortable with regexp I came up with an ugly:data[0].each_char.each_cons(2).with_index.with_object([]) res << i + 1 if (a == ' ' && b != ' ')
. So, I decided to pass over.
– iGian
Mar 24 at 20:02
add a comment |
It would be better if you can get the indices instarts
automatically using the header information. See that each column name does not include a space? Also, the complicated code to get the last index is unnecessary. You can have0
there.
– sawa
Mar 24 at 15:54
1
@sawa, thank you for pointing that0
works anyway as last starting point. I did not added automation for finding the starting points because being not comfortable with regexp I came up with an ugly:data[0].each_char.each_cons(2).with_index.with_object([]) res << i + 1 if (a == ' ' && b != ' ')
. So, I decided to pass over.
– iGian
Mar 24 at 20:02
It would be better if you can get the indices in
starts
automatically using the header information. See that each column name does not include a space? Also, the complicated code to get the last index is unnecessary. You can have 0
there.– sawa
Mar 24 at 15:54
It would be better if you can get the indices in
starts
automatically using the header information. See that each column name does not include a space? Also, the complicated code to get the last index is unnecessary. You can have 0
there.– sawa
Mar 24 at 15:54
1
1
@sawa, thank you for pointing that
0
works anyway as last starting point. I did not added automation for finding the starting points because being not comfortable with regexp I came up with an ugly: data[0].each_char.each_cons(2).with_index.with_object([]) res << i + 1 if (a == ' ' && b != ' ')
. So, I decided to pass over.– iGian
Mar 24 at 20:02
@sawa, thank you for pointing that
0
works anyway as last starting point. I did not added automation for finding the starting points because being not comfortable with regexp I came up with an ugly: data[0].each_char.each_cons(2).with_index.with_object([]) res << i + 1 if (a == ' ' && b != ' ')
. So, I decided to pass over.– iGian
Mar 24 at 20:02
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55313981%2fhow-to-parse-a-string-into-a-hash-table-in-ruby%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown