I would like to know the number of arguments required for a given format string. For example, "%s is my name, and %s is my hair color" would have two arguments required. I could find the number of times % shows up in the string, but that wouldn't work if I really wanted a % in my string and it had %% to signify that. It also doesn't seem at all elegant. Is there a better way?
3 Answers
The simplest way I could come up with is this:
my_string = "%s is my name, and %s is my hair color"
my_string.count('%') - 2 * my_string.count('%%')
6 Comments
PM 2Ring
@PadraicCunningham:
ValueError: incomplete format, for your earlier version. :) Hopefully, the OP is only wanting to test valid format strings.PM 2Ring
@PadraicCunningham: It's a valid string, but I don't see how it's a valid format string. As I said, I get a
ValueError: incomplete format when I try to use "%s is my name, and %s is my hair color %%%" as a format string (on Python 2.6.6).Padraic Cunningham
@PM2Ring, there does not have to be any formatting in the string
my_string = 100% is valid and returns a count of 1, are you saying every string has to have formatting in it?PM 2Ring
@PadraicCunningham: No, I'm certainly not saying that. Just that the OP is only asking about percent-style format strings. So we don't need to worry about handling general strings that may contain percent signs in them.
Padraic Cunningham
@PM2Ring, I think the point is we do have to worry about them as it is perfectly reasonable to expect a user to not add any formatting, I don't think the answer is as trivial as suggested
|
Well, you could use the formatter object for this, since this needs this function for its own formatting purposes. However you have to change your place holders.
import string
fmt = string.Formatter()
my_string = "Hello, {0:s} is my name and {1:s} is my hair color. I have 30% blue eyes"
parts = fmt.parse(my_string)
print list(parts)
This gives:
[('Hello, ', '0', 's', None), (' is my name and ', '1', 's', None), (' is my hair color. I have 30% blue eyes', None, None, None)]
Now it is a matter of filtering the right parts out, namely where the 3rd item in every tuple is not None.
Everything can be changed to a one-liner like this:
len([p for p in fmt.parse(my_string) if p[2] is not None]) # == 2
5 Comments
PM 2Ring
Sure, but that doesn't actually answer the OP's question, which is specifically about old-style
%-based format strings.avanwieringen
Nowhere he specifies that he is bounded to the old-style, and inferior, string formatting. He only uses it at this moment, but nowhere is it said he can not change it.
zondo
I would like to see a similar solution for old-style formatting. It is true, however, that I did not specify; and this does introduce something of which I was previously unaware.
avanwieringen
Okay, clear, let's see if there's a solution for that.
Not exactly efficient - and not entirely serious :) ...
for n in xrange(10, -1, -1):
try:
s % (('',)*n)
except TypeError:
continue
print n
break
6 Comments
PM 2Ring
If it's any consolation, I thought of doing something like this too, except it only works for formats that accept string args like
%s or %r, not numeric formats like %d, %f or %g.James Hopkin
Good point - using 0 rather '' would have been better (numbers are coerced to strings but not vice versa).
PM 2Ring
Oh, yeah! Still, it's not something I'd like to see in production code. :)
zondo
Why limit it to 10? You should use a while loop starting at 0 and add 1 until you get the right answer.
zondo
I might even manage to stay with a score of zero; I guess it's too much to ask.
|
str.formator a regex is the only waystr.formatto find the number of arguments required?fmt.count('%') - 2 * fmt.count('%%')