Method needed for skipping lines
Bruno Desthuilliers
bdesth.quelquechose at free.quelquepart.fr
Wed Oct 31 18:32:48 EDT 2007
Gustaf a écrit :
> Hi all,
>
> Just for fun, I'm working on a script to count the number of lines in
> source files. Some lines are auto-generated (by the IDE) and shouldn't
> be counted. The auto-generated part of files start with "Begin VB.Form"
> and end with "End" (first thing on the line). The "End" keyword may
> appear inside the auto-generated part, but not at the beginning of the
> line.
>
> I imagine having a flag variable to tell whether you're inside the
> auto-generated part, but I wasn't able to figure out exactly how. Here's
> the function, without the ability to skip auto-generated code:
>
> # Count the lines of source code in the file
> def count_lines(f):
> file = open(f, 'r')
1/ The param name is not very explicit.
2/ You're shadowing the builtin file type.
3/ It migh be better to pass an opened file object instead - this would
make your function more generic (ok, perhaps a bit overkill here, but
still a better practice IMHO).
> rows = 0
Shouldn't that be something like 'line_count' ?
> for line in file:
> rows = rows + 1
Use augmented assignment instead:
rows += 1
> return rows
You forgot to close the file.
> How would you modify this to exclude lines between "Begin VB.Form" and
> "End" as described above?
Here's a straightforward solution:
def count_loc(path):
loc_count = 0
in_form = False
opened_file = open(path)
try:
# striping lines, and skipping blank lines
for line in opened_file:
line = line.strip()
# skipping blank lines
if not line:
continue
# skipping VB comments
# XXX: comment mark should not be hardcoded
if line.startswith(';'):
continue
# skipping autogenerated code
if line.startswith("Begin VB.Form"):
in_form = True
continue
elif in_form:
if line.startswith("End"):
in_form = False
continue
# Still here ? ok, we count this one
loc_count += 1
finally:
opened_file.close()
return loc_count
HTH
PS : If you prefer a more functional approach
(warning: the following code may permanently damage innocent minds):
def chain(*predicates):
def _chained(arg):
for p in predicates:
if not p(arg):
return False
return True
return _chained
def not_(predicate):
def _not_(arg):
return not predicate(arg)
return _not_
class InGroupPredicate(object):
def __init__(self, begin_group, end_group):
self.in_group = False
self.begin_group = begin_group
self.end_group = end_group
def __call__(self, line):
if self.begin_group(line):
self.in_group = True
return True
elif self.in_group and self.end_group(line):
self.in_group = False
return True # this one too is part of the group
return self.in_group
def count_locs(lines, count_line):
return len(filter(
chain(lambda line: bool(line), count_line),
map(str.strip,lines)
))
def count_vb_locs(lines):
return count_locs(lines, chain(
not_(InGroupPredicate(
lambda line: line.startswith('Begin VB.Form'),
lambda line: line.startswith('End')
)),
lambda line: not line.startswith(';')
))
# and finally our count_lines function, greatly simplified !-)
def count_lines(path):
f = open(path)
try:
return count_vb_locs(f)
finally:
f.close()
(anyone on doing it with itertools ?-)
More information about the Python-list
mailing list