2

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?

6
  • Using str.format or a regex is the only way Commented Feb 13, 2016 at 12:12
  • 1
    How could I use str.format to find the number of arguments required? Commented Feb 13, 2016 at 12:13
  • I mean, you would have to be using str.format from the get go to find placeholders, there is no builtin method like the Formatter.parse,with old style formatting you will need to parse it yourself Commented Feb 13, 2016 at 12:15
  • I can't think of anything better than fmt.count('%') - 2 * fmt.count('%%') Commented Feb 13, 2016 at 12:23
  • 2
    From pure curiousity, why would you do this? Commented Feb 13, 2016 at 12:28

3 Answers 3

2

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('%%')
Sign up to request clarification or add additional context in comments.

6 Comments

@PadraicCunningham: ValueError: incomplete format, for your earlier version. :) Hopefully, the OP is only wanting to test valid format strings.
@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).
@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?
@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.
@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
|
1

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

Sure, but that doesn't actually answer the OP's question, which is specifically about old-style %-based format strings.
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.
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.
Okay, clear, let's see if there's a solution for that.
I came here from Google looking for a solution for new-style formatting, this works perfectly.
-1

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

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.
Good point - using 0 rather '' would have been better (numbers are coerced to strings but not vice versa).
Oh, yeah! Still, it's not something I'd like to see in production code. :)
Why limit it to 10? You should use a while loop starting at 0 and add 1 until you get the right answer.
I might even manage to stay with a score of zero; I guess it's too much to ask.
|

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.