Passing indented code to compile()
Alex Martelli
aleax at aleax.it
Wed May 7 13:35:14 EDT 2003
Lulu of the Lotus-Eaters wrote:
> "John Wilson" <tug at wilson.co.uk> wrote previously:
> |"just working" it the apex of my ambition at the moment ;-)
>
> There is a function I use in several variants of my smart ASCII markup
> tools. It looks at a code block (or anything), and pushes the block as
> far left as possible, while maintaining relative indents.
>
> def LeftMargin(txt):
> """Remove as many leading spaces as possible from whole block"""
> for l in range(12,-1,-1):
> re_lead = '(?sm)'+' '*l+'\S'
> if re.match(re_lead, txt): break
> txt = re.sub('(?sm)^'+' '*l, '', txt)
> return txt
Hmmm, 'as many as' is somewhat of an overbid, as this is limited to 12
at most (and in JW's app one might easily have more than that).
Wouldn't it be somewhat handier to use, say:
def leftMargin(lines):
def numblanks(line):
return len(line)-len(line.lstrip(' '))
minblanks = min([numblanks(line) for line in lines])
return [line[minblanks:] for line in lines]
A map-fan would of course use min(map(numblanks, lines)) [and
maybe map(lambda x: x[minblanks:], lines) on the return stmt,
and quite possibly a lambda instead of numblanks too], but,
apart from these details, isn't "counting blanks per line",
then taking the min and stripping those off, somewhat better?
Of course, I'm assuming I have the lines in a list of strings
rather than in one big string. But even if the latter were
the case -- and thus re use probably preferable -- I still don't
know that I'd use the "countdown from 12" approach. Is it even
_correct_, in fact?
E.g., given:
import re
def LeftMargin(txt):
"""Remove as many leading spaces as possible from whole block"""
for l in range(12,-1,-1):
re_lead = '(?sm)'+' '*l+'\S'
if re.match(re_lead, txt): break
txt = re.sub('(?sm)^'+' '*l, '', txt)
return txt
blk='''\
pepe
rosso
con
patate'''
print LeftMargin(blk)
the output i observe is:
[alex at lancelot psyco-1.0]$ python xy.py
pepe
rosso
con
patate
[alex at lancelot psyco-1.0]$
which doesn't seem to be what the OP is looking for.
'\n'.join(leftMargin(blk.splitlines())) -- while possibly onerous --
might at least give a satisfactory result.
But, you CAN adapt the 'space counting' to re-and-block use, too:
def relem(txt):
re_leadspace = '(?sm)^ *'
leads = re.findall(re_leadspace, txt)
minblanks = min(map(len, leads))
re_leadspace = '(?sm)^' + ' '*minblanks
txt = re.sub(re_leadspace, '', txt)
return txt
Alex
More information about the Python-list
mailing list