0

I have already read the questions about how coloring text with Python and the Colorama package but I didn't find what I was looking for.

I have some raw text:

Impossible considered invitation him men instrument saw celebrated unpleasant. Put rest and must set kind next many near nay. He exquisite continued explained middleton am. Voice hours young woody has she think equal.

And two lists of words:

good = ["instrument", "kind", "exquisite", "young"]
bad  = ["impossible", "unpleasant", "woody"]

I would like to print that text in a terminal so that words in good are displayed in green and words in bad are displayed in red.

I know I could use colorama, check each word sequentially and make a print statement for this word but it doesn't sound like a good solution. Is there an effective way to do that?

Thomas Reynaud
  • 966
  • 3
  • 8
  • 19
  • Possible duplicate of http://stackoverflow.com/questions/287871/print-in-terminal-with-colors-using-python – kjaquier Sep 12 '16 at 14:31
  • You have to check all the words anyway. – Daniel Lee Sep 12 '16 at 14:34
  • 1
    why is sequentially checking if each word is in one or the other a bad solution? I think it's actually the only solution – Jules G.M. Sep 12 '16 at 14:34
  • Idk looping through the original text and printing doesnt sound like a bad idea. You could define a special print function and use map to do it. – gowrath Sep 12 '16 at 14:37

3 Answers3

2

This should work:

from colorama import Fore, Style

for word in text.split(' '):
    if word in good:
        print Fore.red + word
    elif word in bad:
        print Fore.green + word
    else:
        print Style.RESET_ALL + word
Daniel Lee
  • 7,189
  • 2
  • 26
  • 44
1

You could always do this (though it's probably a little slow):

from colorama import Fore

for word in good:
    text = text.replace(word, Fore.GREEN+word)

for word in bad:
    text = text.replace(word, Fore.RED+word)

print(text)

re.sub might also be interesting here, especially since you probably don't want to replace words that are inside other words so you could use r'\bword\b'.

Wayne Werner
  • 49,299
  • 29
  • 200
  • 290
1

Here is a solution using map. It's definitely no faster than conventional looping :/

from colorama import Fore, Style

def colourise(s, good, bad):
    if s in good:
        return Fore.RED + s
    elif s in bad:
        return Fore.GREEN + s
    else:
        return Style.RESET_ALL + s

text = "Impossible considered invitation him men instrument saw celebrated unpleasant. Put rest and must set kind next many near nay. He exquisite continued explained middleton am. Voice hours young woody has she think equal."

good = ["instrument", "kind", "exquisite", "young"]
bad  = ["impossible", "unpleasant", "woody"]
print(' '.join(map(lambda s: colourise(s, good, bad),text.split())))

Or alternatively:

print(' '.join(colourise(s, good, bad) for s in text.split()))

The second version is probably better.

gowrath
  • 3,136
  • 2
  • 17
  • 32
  • (probably because it still *is* looping… you can’t do this without looping) – poke Sep 12 '16 at 15:02
  • @poke I never claimed it wasn't... It's just using the map functionality which can have advantages/disadvantages over conventional `for i in...` – gowrath Sep 12 '16 at 15:04
  • @gowrath What if I would like to put good and bad as parameters of colourise? – Thomas Reynaud Sep 12 '16 at 15:35
  • @ThomasReynaud I think you could; you'd have to prob define a wrapper function. Illl edit the answer in when I get back; have to go out. – gowrath Sep 12 '16 at 15:50
  • @ThomasReynaud Updated. You can either use a lambda function, or use a list comprehension. The list comprehension is probably better but you can use either. Hope this helps! – gowrath Sep 12 '16 at 21:17