133 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
			
		
		
	
	
			133 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
| #! /usr/bin/python
 | |
| ########################################################################
 | |
| #
 | |
| # reorder and reformat a file in columns
 | |
| #
 | |
| # this utility takes lines from its standard input and reproduces them,
 | |
| # partially reordered and reformatted, on its standard output.
 | |
| #
 | |
| # It has the same effect as a 'sort | column -t', with the exception
 | |
| # that empty lines, as well as lines which start with a '#' sign, are
 | |
| # not affected, i.e. they keep their position and formatting, and act
 | |
| # as separators, i.e. the parts before and after them are each sorted
 | |
| # separately (but overall field widths are computed across the whole
 | |
| # input).
 | |
| #
 | |
| # Options:
 | |
| #   -i:
 | |
| #   --ignore-case:
 | |
| #	Do not consider case when sorting.
 | |
| #   -d:
 | |
| #   --default:
 | |
| #	What to chage empty fields to.
 | |
| #    -s <N>:
 | |
| #    --split=<N>:
 | |
| #       Treat only the first N whitespace sequences as separators.
 | |
| #       line content after the Nth separator will count as only one
 | |
| #       field even if it contains whitespace.
 | |
| #       Example : '-s 2' causes input 'a b c d e' to be split into
 | |
| #       three fields, 'a', 'b', and 'c d e'.
 | |
| #
 | |
| # boards.cfg requires -ids 6.
 | |
| #
 | |
| ########################################################################
 | |
| 
 | |
| import sys, getopt, locale
 | |
| 
 | |
| # ensure we sort using the C locale.
 | |
| 
 | |
| locale.setlocale(locale.LC_ALL, 'C')
 | |
| 
 | |
| # check options
 | |
| 
 | |
| maxsplit = 0
 | |
| ignore_case = 0
 | |
| default_field =''
 | |
| 
 | |
| try:
 | |
| 	opts, args = getopt.getopt(sys.argv[1:], "id:s:",
 | |
| 		["ignore-case","default","split="])
 | |
| except getopt.GetoptError as err:
 | |
| 	print str(err) # will print something like "option -a not recognized"
 | |
| 	sys.exit(2)
 | |
| 
 | |
| for o, a in opts:
 | |
| 	if o in ("-s", "--split"):
 | |
| 		maxsplit = eval(a)
 | |
| 	elif o in ("-i", "--ignore-case"):
 | |
| 		ignore_case = 1
 | |
| 	elif o in ("-d", "--default"):
 | |
| 		default_field = a
 | |
| 	else:
 | |
| 		assert False, "unhandled option"
 | |
| 
 | |
| # collect all lines from standard input and, for the ones which must be
 | |
| # reformatted and sorted, count their fields and compute each field's
 | |
| # maximum size
 | |
| 
 | |
| input_lines = []
 | |
| field_width = []
 | |
| 
 | |
| for line in sys.stdin:
 | |
| 	# remove final end of line
 | |
| 	input_line = line.strip('\n')
 | |
| 	if (len(input_line)>0) and (input_line[0] != '#'):
 | |
| 		# sortable line: split into fields
 | |
| 		fields = input_line.split(None,maxsplit)
 | |
| 		# if there are new fields, top up field_widths
 | |
| 		for f in range(len(field_width), len(fields)):
 | |
| 			field_width.append(0)
 | |
| 		# compute the maximum witdh of each field
 | |
| 		for f in range(len(fields)):
 | |
| 			field_width[f] = max(field_width[f],len(fields[f]))
 | |
| 	# collect the line for next stage
 | |
| 	input_lines.append(input_line)
 | |
| 
 | |
| # run through collected input lines, collect the ones which must be
 | |
| # reformatted and sorted, and whenever a non-reformattable, non-sortable
 | |
| # line is met, sort the collected lines before it and append them to the
 | |
| # output lines, then add the non-sortable line too.
 | |
| 
 | |
| output_lines = []
 | |
| sortable_lines = []
 | |
| for input_line in input_lines:
 | |
| 	if (len(input_line)>0) and (input_line[0] != '#'):
 | |
| 		# this line should be reformatted and sorted
 | |
| 		input_fields = input_line.split(None,maxsplit)
 | |
| 		output_fields = [];
 | |
| 		# reformat each field to this field's column width
 | |
| 		for f in range(len(input_fields)):
 | |
| 			output_field = input_fields[f];
 | |
| 			output_fields.append(output_field.ljust(field_width[f]))
 | |
| 		# any missing field is set to default if it exists
 | |
| 		if default_field != '':
 | |
| 			for f in range(len(input_fields),len(field_width)):
 | |
| 				output_fields.append(default_field.ljust(field_width[f]))
 | |
| 		# join fields using two spaces, like column -t would
 | |
| 		output_line = '  '.join(output_fields);
 | |
| 		# collect line for later
 | |
| 		sortable_lines.append(output_line)
 | |
| 	else:
 | |
| 		# this line is non-sortable
 | |
| 		# sort collected sortable lines
 | |
| 		if ignore_case!=0:
 | |
| 			sortable_lines.sort(key=lambda x: str.lower(locale.strxfrm(x)))
 | |
| 		else:
 | |
| 			sortable_lines.sort(key=lambda x: locale.strxfrm(x))
 | |
| 		# append sortable lines to the final output
 | |
| 		output_lines.extend(sortable_lines)
 | |
| 		sortable_lines = []
 | |
| 		# append non-sortable line to the final output
 | |
| 		output_lines.append(input_line)
 | |
| # maybe we had sortable lines pending, so append them to the final output
 | |
| if ignore_case!=0:
 | |
| 	sortable_lines.sort(key=lambda x: str.lower(locale.strxfrm(x)))
 | |
| else:
 | |
| 	sortable_lines.sort(key=lambda x: locale.strxfrm(x))
 | |
| output_lines.extend(sortable_lines)
 | |
| 
 | |
| # run through output lines and print them, except rightmost whitespace
 | |
| 
 | |
| for output_line in output_lines:
 | |
| 	print output_line.rstrip()
 |