如何在Python中为用户输入添加颜色?

3

我正在创建一个命令行计算器工具,并且希望在用户输入时对其进行格式化,类似于Fish和Powershell所做的(screenshots)。

目前,我能想到的唯一简单的方法是逐个获取字符,然后将格式化的行重新打印到屏幕上。

# This code is probably very dodgy, 
# it's just to give you an idea what I'm thinking
# Use external getch module to get input without echoing to screen
from getch import getch 
inp = ""
while True:
    char = getch()
    if char == '\n': break
    if char == '\b': inp = inp[:-1]
    else: inp += char
    # Print with carriage return so that next input overwrites it
    print(colourFormatInput(inp) + '\r') 
# Outside loop: process input and devliver results

虽然这样做从技术上讲是可行的,但我觉得这需要大量手动工作,并且如果我想添加其他功能(比如使用箭头键来移动光标),将变得更加复杂。

有没有简单的方法可以获得这种功能,而不必自己编写所有代码呢?


这个回答解决了你的问题吗?如何在终端打印彩色文本? - Klaus D.
你尝试过 rich 吗?它可能适合你 https://github.com/willmcgugan/rich - Prayson W. Daniel
不幸的是,这两个都是用于打印输出而不是格式化输入的,因此尽管它们可以帮助格式化,但对于解决我在用户输入时遇到的格式问题并没有太大帮助。 - Miguel Guthridge
3个回答

2
我使用库 colorama
import colorama
import sys


def hook(tp, *args):
    if tp is KeyboardInterrupt:
        print(colorama.Fore.RESET)
        exit()


def colored_input(text: str, color):
    sys.excepthook = hook
    inp = input(text + color)
    print(colorama.Fore.RESET, end="", flush=True)
    sys.excepthook = sys.__excepthook__
    return inp


name = colored_input("What's your name? ", colorama.Fore.RED)
age = colored_input("What's your age? ", colorama.Fore.YELLOW)

print(f"Nice to meet you {name}({age})")

我使用 sys.excepthook 来捕获 KeyboardInterrupt,以便在用户键入 CTRL+C 时重置颜色,然后将原始 excepthook 设置回去 (sys.__excepthook__)。

enter image description here


所以,如果输入是单一颜色,那么这个程序可以正常工作。但是,如果输入是像这样的表达式 [white] 10 [cyan] + [yellow] x [cyan] = [white] 20,那么就无法计算了。 - Miguel Guthridge
@HDSQ 对于误解我很抱歉,你能向我解释一下你的意思吗? - Jonathan1609
给我一分钟,我会快速抓取几个屏幕截图。 - Miguel Guthridge
我想要实现的内容的截图链接:https://imgur.com/a/Z2nafYn - Miguel Guthridge
@HDSQ 你的意思是在打字期间可以设置颜色吗?啊好的。 - Jonathan1609
是的,看起来有其他人已经找到了解决方案,但无论如何还是谢谢你的回答! - Miguel Guthridge

2
你可以使用 prompt_toolkit 来实现这个功能。
如果需要,这里有相关文档: 你可以按照示例添加语法高亮到输入中。

Adding syntax highlighting is as simple as adding a lexer. All of the Pygments lexers can be used after wrapping them in a PygmentsLexer. It is also possible to create a custom lexer by implementing the Lexer abstract base class.

from pygments.lexers.html import HtmlLexer
from prompt_toolkit.shortcuts import prompt
from prompt_toolkit.lexers import PygmentsLexer

text = prompt('Enter HTML: ', lexer=PygmentsLexer(HtmlLexer))
print('You said: %s' % text)

Output of the above

与上面类似,您可以创建定制的prompt_toolkit.lexers.Lexer来进行计算器高亮,就像以下示例一样。在这里,我创建了一个自定义帮助类:
from typing import Callable
from prompt_toolkit.document import Document
from prompt_toolkit.formatted_text.base import StyleAndTextTuples
from prompt_toolkit.formatted_text import FormattedText
from prompt_toolkit.shortcuts import prompt
import prompt_toolkit.lexers
import re

class CustomRegexLexer(prompt_toolkit.lexers.Lexer):
    def __init__(self, regex_mapping):
        super().__init__()
        self.regex_mapping = regex_mapping

    def lex_document(self, document: Document) -> Callable[[int], StyleAndTextTuples]:
        def lex(_: int):
            line = document.text
            tokens = []
            while len(line) != 0:
                for pattern, style_string in self.regex_mapping.items():
                    match: re.Match = pattern.search(line)

                    if not match:
                        continue
                    else:
                        # print(f"found_match: {match}")
                        pass
                    match_string = line[:match.span()[1]]
                    line = line[match.span()[1]:]
                    tokens.append((style_string, match_string))
                    break
            return tokens
        return lex

现在我们已经实现了上述帮助类,可以创建我们的正则表达式模式及其相应的样式。要了解有关样式字符串中可以包含哪些内容,请转到此页面
# Making regex for different operators. Make sure you add `^` anchor
# to the start of all the patterns
operators_allowed = ["+", "-", "/", "*", "(", ")", "=", "^"]
operators = re.compile("^["+''.join([f"\\{x}" for x in operators_allowed])+"]")
numbers = re.compile(r"^\d+(\.\d+)?")
text = re.compile(r"^.")


regex_mapping = {
    operators: "#ff70e5",  # Change colors according to your requirement
    numbers: "#ffa500",
    text: "#2ef5ff",
}

MyCalculatorLexer = CustomRegexLexer(regex_mapping)

有了创建的词法分析器,现在您可以在函数提示中使用该词法分析器:
text = prompt("Enter Equation: ", lexer=MyCalculatorLexer)

# Or

def input_maths(message):
    return prompt(message, lexer=MyCalculatorLexer)

text = input_maths("Enter Equation: ")

这里是一些示例输出:

Example Output

现在一切都正常了。还要检查一下 prompt_toolkit ,你可以像gallery中展示的那样创建大量自定义内容。

出现错误 type object 'CalculatorLexer' has no attribute 'lex_document' - Miguel Guthridge
请等待我的电脑重新启动。很不幸,我已经让它崩溃两次了。 - AmaanK
看起来这可能是正则表达式词法分析器本身的问题,因为使用 python -m pygments -x -l lexer.py:CalculatorLexer temp.txt 运行它,其中 temp.txt 是一些随机的数学输入,会导致它冻结。 - Miguel Guthridge
请再尝试一次以上内容,我已经尝试通过添加换行符正则表达式进行更正。如果仍然无法解决问题,您可以将其标记为未解决并继续查看 prompt-toolkit 文档 :( - AmaanK
让我们在聊天室里继续这个讨论 - AmaanK
显示剩余2条评论

-1

另一个例子:


CGREEN = '\33[32m'
CYELLOW = '\33[33m'
CBLUE = '\33[34m'
CVIOLET = '\33[35m'
CBEIGE = '\33[36m'
CWHITE = '\33[37m'
CGREY = '\33[90m'
CRED = '\033[91m'
CYELLOW = '\33[33m'
CYELLOW2 = '\33[93m'
CEND = '\033[0m'

print(CGREEN + "This is green text" + CEND)
print(CYELLOW + "This is yellow text" + CEND)

# Another interesting example (courtesy: https://www.lihaoyi.com/post/BuildyourownCommandLinewithANSIescapecodes.html)

for i in range(0, 16):
    for j in range(0, 16):
        code = str(i * 16 + j)
        colorCode = u"\u001b[48;5;" + code + "m"
        print(colorCode + " Color {} ".format(code) + CEND)

这只是简单地以彩色打印文本,但这个答案并没有展示与 OP 要求的输入相关的任何内容,并且跨平台不支持为您的代码着色,您也没有给出为什么这是正确答案的任何信息。就像没有人要求编写一个以所有颜色打印文本的程序一样,请重新阅读问题,如果您没有理解的话。 - AmaanK

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接