Nicely formatting output to console, specifying number of tabs

前端 未结 7 1278
盖世英雄少女心
盖世英雄少女心 2020-12-24 02:01

I am generating a script that is outputting information to the console. The information is some kind of statistic with a value. So much like a hash.

So one value\'s

相关标签:
7条回答
  • 2020-12-24 02:10

    String has a built-in ljust for exactly this:

    x = {"foo"=>37, "something long"=>42, "between"=>99}
    x.each { |k, v| puts "#{k.ljust(20)} #{v}" }
    # Outputs:
    #  foo                  37
    #  something long       42
    #  between              99
    

    Or, if you want tabs, you can do a little math (assuming tab display width of 8) and write a short display function:

    def tab_pad(label, tab_stop = 4)
      label_tabs = label.length / 8
      label.ljust(label.length + tab_stop - label_tabs, "\t")
    end
    
    x.each { |k, v| puts "#{tab_pad(k)}#{v}" }
    # Outputs: 
    #  foo                  37
    #  something long       42
    #  between              99
    
    0 讨论(0)
  • 2020-12-24 02:12

    You typically don't want to use tabs, you want to use spaces and essentially setup your "columns" your self or else you run into these types of problems.

    0 讨论(0)
  • 2020-12-24 02:13

    There is usually a %10s kind of printf scheme that formats nicely.
    However, I have not used ruby at all, so you need to check that.


    Yes, there is printf with formatting.
    The above example should right align in a space of 10 chars.
    You can format based on your widest field in the column.

    printf ([port, ]format, arg...)

    Prints arguments formatted according to the format like sprintf. If the first argument is the instance of the IO or its subclass, print redirected to that object. the default is the value of $stdout.

    0 讨论(0)
  • 2020-12-24 02:18

    I wrote a thing

    • Automatically detects column widths
    • Spaces with spaces
    • Array of arrays [[],[],...] or array of hashes [{},{},...]
    • Does not detect columns too wide for console window

      lists = [ [ 123, "SDLKFJSLDKFJSLDKFJLSDKJF" ], [ 123456, "ffff" ], ]

    array_maxes

    def array_maxes(lists)
      lists.reduce([]) do |maxes, list|
        list.each_with_index do |value, index|
          maxes[index] = [(maxes[index] || 0), value.to_s.length].max
        end
        maxes
      end
    end
    
    array_maxes(lists)
    # => [6, 24]
    

    puts_arrays_columns

    def puts_arrays_columns(lists)
      maxes = array_maxes(hashes)
      lists.each do |list|
        list.each_with_index do |value, index|
          print " #{value.to_s.rjust(maxes[index])},"
        end
        puts
      end
    end
    
    puts_arrays_columns(lists)
    
    # Output:
    #     123, SDLKFJSLDKFJSLDKFJLSDKJF,
    #  123456,                     ffff,
    

    and another thing

    hashes = [
      { "id" => 123,    "name" => "SDLKFJSLDKFJSLDKFJLSDKJF" },
      { "id" => 123456, "name" => "ffff" },
    ]
    

    hash_maxes

    def hash_maxes(hashes)
      hashes.reduce({}) do |maxes, hash|
        hash.keys.each do |key|
          maxes[key] = [(maxes[key] || 0), key.to_s.length].max
          maxes[key] = [(maxes[key] || 0), hash[key].to_s.length].max
        end
        maxes
      end
    end
    
    hash_maxes(hashes)
    # => {"id"=>6, "name"=>24}
    

    puts_hashes_columns

    def puts_hashes_columns(hashes)
      maxes = hash_maxes(hashes)
    
      return if hashes.empty?
    
      # Headers
      hashes.first.each do |key, value|
        print " #{key.to_s.rjust(maxes[key])},"
      end
      puts
    
      hashes.each do |hash|
        hash.each do |key, value|
          print " #{value.to_s.rjust(maxes[key])},"
        end
        puts
      end
    
    end
    
    puts_hashes_columns(hashes)
    
    # Output:
    #      id,                     name,
    #     123, SDLKFJSLDKFJSLDKFJLSDKJF,
    #  123456,                     ffff,
    

    Edit: Fixes hash keys considered in the length.

    hashes = [
      { id: 123,    name: "DLKFJSDLKFJSLDKFJSDF", asdfasdf: :a  },
      { id: 123456, name: "ffff",                 asdfasdf: :ab },
    ]
    
    hash_maxes(hashes)
    # => {:id=>6, :name=>20, :asdfasdf=>8}
    

    Want to whitelist columns columns?

    hashes.map{ |h| h.slice(:id, :name) }
    # => [
    #  { id: 123,    name: "DLKFJSDLKFJSLDKFJSDF" },
    #  { id: 123456, name: "ffff"                 },
    #]
    
    0 讨论(0)
  • For future reference and people who look at this or find it... Use a gem. I suggest https://github.com/wbailey/command_line_reporter

    0 讨论(0)
  • 2020-12-24 02:32

    Provided you know the maximum length to be no more than 20 characters:

    printf "%-20s %s\n", value_name, value
    

    If you want to make it more dynamic, something like this should work nicely:

    longest_key = data_hash.keys.max_by(&:length)
    data_hash.each do |key, value|
      printf "%-#{longest_key.length}s %s\n", key, value
    end
    
    0 讨论(0)
提交回复
热议问题