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;








2















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









share|improve this question






























    2















    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









    share|improve this question


























      2












      2








      2








      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









      share|improve this question
















      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






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Mar 24 at 15:45









      sawa

      134k31211309




      134k31211309










      asked Mar 23 at 13:01









      Emmanuel AmoduEmmanuel Amodu

      86111




      86111






















          3 Answers
          3






          active

          oldest

          votes


















          1














          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).






          share|improve this answer




















          • 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 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











          • 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


















          5














          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"]





          share|improve this answer

























          • 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


















          4














          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", ...





          share|improve this answer

























          • 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





            @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











          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
          );



          );













          draft saved

          draft discarded


















          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









          1














          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).






          share|improve this answer




















          • 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 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











          • 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














          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).






          share|improve this answer




















          • 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 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











          • 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








          1







          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).






          share|improve this answer















          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).







          share|improve this answer














          share|improve this answer



          share|improve this answer








          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 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











          • 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





            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 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











          • 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













          5














          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"]





          share|improve this answer

























          • 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















          5














          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"]





          share|improve this answer

























          • 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













          5












          5








          5







          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"]





          share|improve this answer















          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"]






          share|improve this answer














          share|improve this answer



          share|improve this answer








          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 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
















          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











          4














          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", ...





          share|improve this answer

























          • 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





            @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















          4














          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", ...





          share|improve this answer

























          • 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





            @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













          4












          4








          4







          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", ...





          share|improve this answer















          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", ...






          share|improve this answer














          share|improve this answer



          share|improve this answer








          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 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





            @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

















          • 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





            @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
















          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

















          draft saved

          draft discarded
















































          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.




          draft saved


          draft discarded














          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





















































          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







          Popular posts from this blog

          Kamusi Yaliyomo Aina za kamusi | Muundo wa kamusi | Faida za kamusi | Dhima ya picha katika kamusi | Marejeo | Tazama pia | Viungo vya nje | UrambazajiKuhusu kamusiGo-SwahiliWiki-KamusiKamusi ya Kiswahili na Kiingerezakuihariri na kuongeza habari

          Swift 4 - func physicsWorld not invoked on collision? The Next CEO of Stack OverflowHow to call Objective-C code from Swift#ifdef replacement in the Swift language@selector() in Swift?#pragma mark in Swift?Swift for loop: for index, element in array?dispatch_after - GCD in Swift?Swift Beta performance: sorting arraysSplit a String into an array in Swift?The use of Swift 3 @objc inference in Swift 4 mode is deprecated?How to optimize UITableViewCell, because my UITableView lags

          Access current req object everywhere in Node.js ExpressWhy are global variables considered bad practice? (node.js)Using req & res across functionsHow do I get the path to the current script with Node.js?What is Node.js' Connect, Express and “middleware”?Node.js w/ express error handling in callbackHow to access the GET parameters after “?” in Express?Modify Node.js req object parametersAccess “app” variable inside of ExpressJS/ConnectJS middleware?Node.js Express app - request objectAngular Http Module considered middleware?Session variables in ExpressJSAdd properties to the req object in expressjs with Typescript