How to format the 2nd field in a record with word wrap?

All-

Here’s a record formatting question for you:

Say I have a record like in this format…

nnnnnThis is a sample sentence meant to demonstrate desired word wrapping to make the appearance of a virtual column from a single long string that doesn’t have any hard returns.

… and I want to format it to look something like this:

nnnnn This is a sample sentence meant to
demonstrate desired word wrapping
to make the appearance of a virtual
column from a single long string
that doesn’t have any hard returns.

where:

  • nnnnn is a 5 character string.
  • is a tab character (to be replaced by three spaces).
  • The first space after every 35 or so characters in the sentence (2nd field of the record) is replaced by a hard return plus eight spaces.
  • The sample above is one of many records in a file, separated by a hard return.

Thanks again, friends!

-Kurt

I’ll throw my hat in the ring as well!

#!/usr/local/bin/ruby -w

USAGE =<<'EOF’
Usage: virtcol.rb [-w width] [file] …

  • Width: minimum 5, default 50
  • STDIN read if no files specified.
    EOF
···

############################################################################

Read input from a line

“nnnnnNow is the time … aid of the party”

and produce

nnnnn Now is the time for all good

men to come to the aid of

the party.

############################################################################

class VirtualColumnDemo
DEFAULT_WIDTH = 40

‘input’ is an array of lines in the format described above.

def initialize(input, width=DEFAULT_WIDTH)
# Convert the raw input into an array of Lines.
@lines = input.map { |il| Line.new(il, width) }
end

def VirtualColumnDemo.from_file(file, width=DEFAULT_WIDTH)
lines = file.readlines
VirtualColumnDemo.new(lines, width)
end

Pretty-print each line of data followed by a blank line.

def display
for line in @lines
puts line.generate_text
puts
end
end

private

############################################################################

Encapsulates a single piece of data containing the left column ‘header’

and right column ‘text’.

############################################################################

class Line
attr_accessor :width
attr_reader :header, :text

def initialize(raw_line, width)
  @width = width
  @header, @text = raw_line.chomp.split(/\t/)
  @header ||= ""
  @text   ||= ""
end

# -> Array of lines fully formatted.
def generate_text
  # Split the text at the first space before 'width'.  If there is none,
  # take the one after; failing that, the end of the String.
  text = @text.dup
  split_text = []
  while text.length > 0
    last_space = text.rindex(/\s/, width) || text.index(/\s/, width-1)

-1
new_line = text.slice!(0…last_space)
split_text << new_line.strip
end
split_text = [""] if split_text == []

  # Now add header before first line and 8 spaces before each other.
  output = split_text
  output.each_with_index do |line,i|
    if i == 0
      line.replace( ("%-8s" % @header) + line )
    else
      line.replace("        " + line)
    end
  end

  # That's it.
  output
end

end
end

############################################################################

(MAIN)

############################################################################

Sort out arguments.

width = 40 # Default value
if ARGV[0] == "-w"
ARGV.shift
begin
width = Integer(ARGV.shift)
rescue
$stderr.puts "\n*** Ignoring width field; it doesn’t compute.\n\n"
end
end
width = [5, width].max

Run the demo.

vc = VirtualColumnDemo.from_file(ARGF, width)
vc.display