#!/usr/local/cpython-3.5/bin/python3 '''Randomize the lines of input, but preserve a degree of locality''' from __future__ import print_function import os import sys import random sys.path.insert(0, '/usr/local/lib') import readline0 def usage(retval): '''Output a usage message''' if retval == 0: write = sys.stdout.write else: write = sys.stderr.write write('Usage: {} -n 10 --help\n'.format(sys.argv[0])) write('-n 10 says to use a randomizing window of 10. It is possible for values to move further than this\n') write(' but it\'s vanishingly unlikely\n') write('--newline-in Read lines separated by newlines instead of nulls\n') write('--newline-out Write lines separated by newlines instead of nulls\n') write('--no-newline-warning Do not warn about a single null-terminated line containing newlines\n') sys.exit(retval) def main(): '''Main function''' number = 10 newline_in = False newline_out = False newline_warning = True while sys.argv[1:]: if sys.argv[1] == '-n': number = int(sys.argv[2]) del sys.argv[1] elif sys.argv[1] == '--newline-in': newline_in = True elif sys.argv[1] == '--newline-out': newline_out = True elif sys.argv[1] == '--no-newline-warning': newline_warning = False elif sys.argv[1] in ('-h', '--help'): usage(0) else: sys.stderr.write('{}: Unrecognized option: {}\n'.format(sys.argv[0], sys.argv[1])) usage(1) del sys.argv[1] process(number, newline_warning, newline_in, newline_out) def process(number, newline_warning, newline_in, newline_out): '''Process the input''' list_ = [] if newline_in: separator = b'\n' else: separator = b'\0' for line in readline0.readline0(0, separator=separator): list_.append(line) if newline_warning: if len(list_) == 1: count = list_[0].count(b'\n') if count >= 1: string = '{}: Warning: 1 line with {} newlines found:\n'.format(sys.argv[0], count) + \ 'Maybe use -newline-in or --no-newline-warning?\n' sys.stderr.write(string) # We don't really care about odd numbers being floor'd number_over_2 = number // 2 len_list_minus_1 = len(list_) - 1 for lineno, line in enumerate(list_): left = max(0, lineno - number_over_2) right = min(lineno + number_over_2, len_list_minus_1) # print('left is {}, right is {}'.format(left, right)) random_int = random.randint(left, right) list_[lineno], list_[random_int] = list_[random_int], list_[lineno] if newline_out: separator = b'\n' else: separator = b'\0' for line in list_: os.write(1, line + separator) main()