Reputation: 50995
I've had to create code similar to this several times:
if condition():
word = " not"
else:
word = ""
print "A five ounce bird could{0} carry a one pound coconut".format(word)
I've stripped the problem down to its bones here, in "practice" there'd be extra variables for "A"
, "five"
, "bird"
, "a"
, "one"
, and "coconut"
so that they might all change, and along with them, added plural s-es and whatnot.
It has always struck me as somewhat less than satisfying. The extra space required before "not"
and the lack of a space before {0}
both irk, but since I don't want two spaces there if word
is empty, I can't see any other way to do it.
Creating two separate messages breaks with DRY and is sometimes not even viable because of the number of possible combinations.
Is there a more elegant way to do this?
Upvotes: 4
Views: 2865
Reputation: 9172
I'd do...
word = ("could" if not condition() else "could not")
print "A five ounce bird {0} carry a one pound coconut".format(word)
:P
Edit: for the general case, which is what you want, I'd go by composition. Eg. (ok, this is too Go4 and simplistic for my liking, but makes the point):
class Agglutinator(list):
def __str__(self):
return self._separator.join(str(x) for x in self)
class Paragraph(Agglutinator):
"""Returns dot separated sentences"""
_separator = '. '
class Sentence(Agglutinator):
"""Returns comma separated clauses"""
_separator = ', '
class Clause(Agglutinator):
"""Returns space separated words"""
_separator = ' '
c1 = Clause(["A", "number", "of", "words", "make", "a", "clause"])
c2 = Clause(["and", "a", "number", "of", "clauses", "make", "a", "sentence"])
c3 = Clause(["A", "collection", "of", "sentences", "makes", "a", "paragraph"])
s1 = Sentence([c1, c2])
s2 = Sentence([c3])
print Paragraph([s1, s2])
which gives you:
A number of words make a clause, and a number of clauses make a sentence. A collection of sentences makes a paragraph
Elaborating a little bit on it you may make Sentence
capitalize the first word, etc.
Upvotes: 1
Reputation: 50995
I'll add another possibility that I just thought of myself. Subclass string.Formatter
and add a custom converter, so you can type
fmt = MyFormatter()
print fmt("Problem {not!w} solved", not="")
The formatter would then remove the space before all fields with the !w
converter if the variable was empty/not specified. This requires reimplementing at least the vformat
and convert_field
methods, but it should be quite doable.
Upvotes: 0
Reputation: 18727
One other way to handle this, but a am not sure if it is what you are looking for
word = "not"
print "A five ounce bird could{0} carry a one pound coconut".format(" "+word if condition() else "")
Ok, one more approach. But in fact, nearly all of them are similar or same...
def format_word(word):
if word:
return " " + word
else:
return ""
print "A five ounce bird could{0} carry a one pound coconut".format(format_word(word))
But probably, all of the will look irking, since they are in fact similar...
Final dirty approach might be:
if condition():
word = "not"
else:
word = ""
wrd = "A five ounce bird could {0} carry a one pound coconut".format(word)
print wrd.replace(" ", " ") # replace all double spaces with singular one...
but yes, it is dirty too...
Upvotes: 1
Reputation: 59446
Since the rules where a space must be and where not are clear in English (and in other languages I know), you could use a simple list of all sentence parts (e. g. ['If', 'there', 'are', 'commas', ',', 'we', 'insert', 'them', '.']
) and then write a specialised join function which applies English rules on where spaces must be inserted (e. g. between words, after commas, before opening parentheses, …).
Upvotes: 1
Reputation: 212955
Create a list of words, insert if necessary, and then ' '.join(words)
them.
If there are commas/periods, build a sentence structure:
[['If', 'there', 'are', 'periods'], ', ', ['build', 'a', 'sentence', 'structure'], '.']
with respective spaces in the interpunction (space after comma, space before parenthesis,…) and then ' '.join()
the words within groups and ''.join()
the individual groups. (Thanks to @Alfe for the suggestion with joining words and groups differently).
Upvotes: 3
Reputation: 236034
For the " not"
case, keep it simple:
print "A five ounce bird could{0} carry a one pound coconut".format(" not" if condition() else "")
Upvotes: 1