Your approach is basically reasonable, but you aren't taking advantages of Python's more powerful features, or any of the more interesting parts of the standard library.
re.search
A minor point to start with. You're making a regex like so:
prog=re.compile(".*"+regex+".*")
Presumably so that you get an unanchored match (i.e., one which can start at any point in the string).
re
has a method re.search
which will do unanchored matching by default; you can anchor the match to the start of the string with ^
, as you would expect. See search() vs. match() in the documentation.
Manipulating whole data structures
There are a number of specific points below, but the broad thrust of them is that you will have a much nicer time doing large-scale operations on whole data structures, rather than fiddling around with indexes and individual elements. This is true in most languages, but one of the strengths of Python is the rich set of data structures and operations which are available built-in or in the standard library.
itertools.compress
There is a wonderful module in the standard library called itertools
. This library is my first thought in Python whenever I want to do something involving sequences of any kind, and it contains a little function called compress
which will do a lot of the work for your program.
Basically, you give compress
a sequence of data items and a sequence of selectors, and you get back a sequence of those data items for which the selector is true. So in your example, matching your regex against the columns would give you the "selector":
[False, True, False, True, False]
(I'll mention how to generate this simply in a moment). You would then want to modify this to also pass through the row header, so you have the selector:
[True, True, False, True, False]
then, doing itertools.compress
for a randomly-selected row:
itertools.compress(['a', 2, 9, 6, 1], [True, True, False, True, False])
=> ['a', 2, 6]
you can then just print that list to print the (filtered) row.
Note that you could also do this filtering yourself, using a list comprehension; however, itertools
has the twin advantages of being common (hence readable) and carefully optimized (hence fast).
join
Once you can easily generate lists containing exactly the elements you want to output, you don't have to fiddle around doing print('\t', tokens[col], end='')
and similar; you can just do:
print('\t'.join(tokens))
(assuming you have already filtered your tokens using compress
or similar).
List comprehensions
List comprehensions are one of Python's most pleasant features. They're far too large a topic for me to sensibly explain in an answer here; that link will give you a good introduction, and there are many other articles and introductions around.
Roughly speaking, list comprehensions (and their cousins, generator expressions) are a nice syntax for creating sequences from sequences, doing "something" (transforming, selecting, etc.) on the way.
For example, you could write a list comprehension like this:
[reg.search(t) for t in tokens]
If reg
is [a|c]
, and tokens
is ['', 'a', 'b', 'c', 'd']
, this will produce:
[False, True, False, True, False]
which you will recall is exactly what you need to feed to compress
to filter to just those columns. (Actually, it will produce a list of None
s and regex match objects, but those evaluate to False
/True
in a boolean context, so don't worry too much about that).
argparse
module to help parse the console inputs instead of hard coding them in. docs.python.org/2.7/library/argparse.html \$\endgroup\$