Home > Mobile >  remove last character from looping Hash
remove last character from looping Hash

Time:10-10

can you help me to solve this problem with this code?

total_user_input = []

while true
  print "Field Name: "
  user_input = gets.chomp
  break if user_input.empty?
  total_user_input << user_input
end


total_user_input.each do |input|
  aa = input.split(":").reduce {|first, second| "  \t'#{first}': '#{second}',\r\n".gsub("'",'"') }
  puts aa.chomp(',')
end

and the result I get

"name": "string",
"desc": "string",
"price": "integer",

but what I want is just remove the last comma only

"name": "string",
"desc": "string",
"price": "integer"

thank you for helping me

CodePudding user response:

I don't know actualy what your scenario But I base on your expected and You can try it.

total_user_input = [
  "name:test",
  "age:30"
]

input_length = total_user_input.size
total_user_input.each_with_index do |input, index|
  aa = input.split(":").reduce {|first, second| "  \t'#{first}': '#{second}',\r\n".gsub("'",'"') }
  aa = aa.gsub(',', '') if index == input_length - 1 # or aa.slice(-1)
  puts aa
end

=> My result

"name": "test",
"age": "30"

CodePudding user response:

TL;DR

I'm happy to answer the question you actually asked, but it needs to be pointed out that what you're doing is inherently an anti-pattern and not idiomatic Ruby.

I'll first show you a better way to do what you're doing, using stages of transformation rather than a single idiomatic method chain. Next I'll cover some alternatives that will help you with the String data you've already constructed.

At the end, I also provide a few caveats that you should generally be aware of, but aren't essential to answering your question. They're still useful, and will definitely help with addressing these sorts of problems when you're trying to debug something.

The Right Way

First of all, don't do this in this way at all. Instead, just take your pairs of inputs and convert them to a Hash or JSON directly. For example:

require "json"

pp total_user_input
#=> ["name", "string", "desc", "string", "price", "integer"]

aa = total_user_input.each_slice(2).to_h
#=> {"name"=>"string", "desc"=>"string", "price"=>"integer"}

puts JSON.pretty_generate aa
{
  "name": "string",
  "desc": "string",
  "price": "integer"
}

This will transform your input in stages, and print a string to STDOUT suitable for writing to a file or otherwise pretty-printing as JSON.

Your Original Question Answered

If you insist on trying to modify the given String, listed in your example as:

your_pseudo_json = <<~STRING
  "name": "string",
  "desc": "string",
  "price": "integer",
STRING

you have limited options. You're also complicating your life by using Windows-style newlines instead of Unix-style ones, but you can handle this one of two ways:

  1. Use the $\ record separator for your system, possibly defined by default, or set it yourself. Then you can just use String#chomp. For example:

     # If you have to set it explicitly, do so by assigning to $/
     # NB: You may not. I don't have a Windows system to check.
     $/ = "\r\n"
    
     your_pseudo_json.chomp!(",#{$/}")
    
  2. Use an anchored regular expression to remove just the items at the end. For example:

     your_pseudo_json.sub! /(,(?:\r?\n)\z)/, ""
    
  3. If you're running a newer Ruby sthat supports String#delete_suffix! then you can do this almost like #chomp, but with a simple String without interpolation. For example:

     # for Windows line endings
     your_pseudo_json.delete_suffix! ",\r\n"
    
     # for *nix-style line endings
     your_pseudo_json.delete_suffix! ",\n"
    

Caveats

Use Non-Bang Methods for Testing in Irb or Pry

As a testing note, use the non-bang methods of #chomp, #sub, and #delete_suffix in your REPL for testing, so that you don't have to keep recreating your string while you experiment. The bang methods will modify your string in-place, unless you're running with frozen strings enabled by default.

Frozen Strings

Also, note that if you're using the frozen strings pragma in your program, e.g.:

  • # frozen_string_literal: true at the top of your .rb file
  • RUBYOPT="--enable-frozen-string-literal" in your environment when calling your REPL

then use the non-bang methods and assign the results back to a different (or even the same) variable. Duplicating unfrozen copies of frozen strings is outside the scope of your current question, so I wouldn't even mention it at all except to prevent general bike-shedding by other readers on the subject. :)

  • Related