11

Suppose I have 3 python strings and I can format all 3 of them with 2 separating spaces between them like in the following:

h="hello"
m="my"
w="world"

print("{} {} {}".format(h,m,w))

or using

print("%s %s %s" % (h,m,w))

Suppose now that I am sure that both h and w have values but m might be an empty string. The two code fragments above would result with "hello{two speces here}world.

I know that I can use different functions and conditional expressions to either do the formatting by code such as in

print(h+" " + m+(" " if len(m)>0 else "") + w)

or pick a different formatting string

print(("{} {} {}" if len(m)>0 else "{}{} {}").format(h,m,w))

based on the length of m.

My Q is Can this be done using the formatting strings ? (e.g. some format modifier that will pad with 1 space if its parameter is not empty).

1
  • 1
    I checked the docs, I don't think you can. Commented Oct 25, 2017 at 8:00

5 Answers 5

6

not sure it's very convenient, but there's a way, generating space or not depending on the "truth" value of the strings:

h="hello"
m="my"
w="world"

print("{}{}{}{}".format(h," "*bool(m),m,w))

result:

hello my world

now set m to empty string, you get

hello world
Sign up to request clarification or add additional context in comments.

Comments

5

I'm not sure this can be done with formatting strings along.

I would do this with python string join.

strings = [h, m, w]
print " ".join([s for s in strings if len(s)>0])

The inner part [s for s in strings if len(s)>0] creates a list with just the non zero length strings. Then " ".join(...) joins those together with a space between.

4 Comments

While this answer is not wrong, it does not address OP's question: Can this be done using the formatting strings?
besides " ".join([s for s in strings if len(s)>0]) sucks: " ".join([s for s in strings if s]) is more pythonic
@cᴏʟᴅsᴘᴇᴇᴅ completely agree, I can't see a way to do this with pure formatting, but I don't want to say it's impossible.
' '.join(filter(None, strings)) would also work and is faster for this case.
3

I will accept @Jean-François Fabre 's answer that basically answers my question as I specified it by saying that (at least for now) there is no answer to this using only string formatting (i.e. if the variables to be formated are just h, m & w without additional processing).

However, using the concept of boolean operators on strings as in his answer i think i will use:

print("{}{}{} {}".format(h,m and " " ,m , w))

This has the disadvantage of giving the the person reading it the feeling that 4 values are being formated (which is the case technically but not semantically) but I do think that the shortness and simplicity of the expressions here overcome the negative aspect.

Readability could be yet improved by using Parametrized formats as suggested by @Tsingyi but using the following:

print("{}{pad}{} {}".format(h, m , w, pad = m and " "))

NOTE:
THE FOLLOWING IS NOT WORKING CODE AT THE TIME OF WRITING:
Hopefully in the future maybe we could do something like:

print("{}{: >?} {}".format(h,m,w))

with the semantics of "optionally (if m then) align it to the right and pad with one additional space to its left", or

print("{} {: <?}{}".format(h,m,w))

with the semantics of "optionally (if m then) align it to the left and pad with one additional space to its right"

similar variants might be helpful for optional formatting of currency symbols e.g.

print("{:$>?}{}".format(s))  

to yield either an empty string or $123

One final (long) note: at some point during my research of this issue I thought that I might be able to do something like this:

def extend_string_formatting():
    try:
       '{:left-pad-if-not-empty}'.format('')
    except ValueError:
        original_formatter=str.__format__

        def extended_formatter(self, format):
            if (format == 'left-pad-if-not-empty'):
                return ' ' + self if self else ''
            return original_formatter(self, format)

        str.__format__=extended_formatter
extend_string_formatting()

but it turns out that this results with:

Traceback (most recent call last):
  File "<input>", line 3, in extend_string_formatting
ValueError: Invalid format specifier
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "<input>", line 12, in extend_string_formatting
TypeError: can't set attributes of built-in/extension type 'str'

maybe this can be achieved using something like what is described here: https://stackoverflow.com/a/15975791/25412

1 Comment

2

I believe this is not possible with the formatting strings all alone.

if you have to use the formatting strings you could use re module to get rid of extra spaces after applying the formatting:

    import re

    h="hello"
    m="my"
    w="world"

    p = re.compile('\s+')

    print p.sub(" ","{} {} {}".format(h,m,w))

which would output:

    hello my world

with an empty string:

    print p.sub(" ","{} {} {}".format(h,"",w))

would output:

    hello world

Is this what you are after?

Comments

0

You could use the Parametrized formats with new style string formatting, but you still have to test whether m is empty or not by yourself.

def fmt(h, m, w):
    return return '{}{:>{wd}} {}'.format(h, m, w, wd=len(m)+1 if m else 0)

>>> fmt('hello', 'my', 'world')
'hello my world'
>>> fmt('hello', '', 'world')
'hello world'

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.