Lauritz V. Thaulow
Lauritz V. Thaulow

Reputation: 50995

Maybe add extra sentence/word to string

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

Answers (7)

Ricardo Cárdenes
Ricardo Cárdenes

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

Lauritz V. Thaulow
Lauritz V. Thaulow

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

Mp0int
Mp0int

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

Alfe
Alfe

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

eumiro
eumiro

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

Óscar López
Óscar López

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

NPE
NPE

Reputation: 500475

Creating two separate messages breaks with DRY

If you care about i18n, then creating two separate messages is probably the only reasonable way to do it.

Upvotes: 2

Related Questions