Python 3执行input()方法时如何输入可删除换行符并通过异常终止输入
需求可以实现
默认的input()和sys.stdin.readlines()都基于行缓冲模式,该模式下换行符会被系统当做输入终止符,一旦输入就无法退格删除。我们可以通过修改终端的输入模式,自行逐字符处理输入来满足所有要求,核心逻辑是绕开系统默认的行缓冲规则,自己维护输入缓冲区。
实现思路
- 先保存终端的原始配置,避免程序异常退出后终端输入行为异常
- 将终端切换为cbreak模式(类Unix平台)或直接逐字符读取(Windows平台):该模式下输入不需要等待换行即可被程序捕获,同时保留
Ctrl+C触发KeyboardInterrupt的能力 - 逐字符处理输入:
- 普通字符(包括换行符)直接存入自定义缓冲区并回显
- 退格字符触发时删除缓冲区最后一位,同时更新终端显示
- 自定义输入终止快捷键(比如
Ctrl+D,和系统shell默认行为一致),触发时返回缓冲区完整内容
- 无论流程正常结束还是被中断,都先恢复终端原始配置再退出
代码实现
适用Unix/Linux/macOS平台
import sys import tty import termios def multi_line_input(prompt: str = "") -> str: fd = sys.stdin.fileno() # 保存终端原始配置 original_attr = termios.tcgetattr(fd) buffer = [] try: # 切换到cbreak模式,保留信号处理能力 tty.setcbreak(fd) if prompt: sys.stdout.write(prompt) sys.stdout.flush() while True: char = sys.stdin.read(1) # 处理Ctrl+C终止输入 if ord(char) == 3: raise KeyboardInterrupt # 处理退格 elif char in ("\x7f", "\b"): if buffer: buffer.pop() # 同步更新终端显示 sys.stdout.write("\b \b") sys.stdout.flush() # 处理Ctrl+D结束输入 elif ord(char) == 4: sys.stdout.write("\n") sys.stdout.flush() return "".join(buffer) # 普通字符包括换行直接存入缓冲区 else: buffer.append(char) sys.stdout.write(char) sys.stdout.flush() finally: # 强制恢复终端原始配置 termios.tcsetattr(fd, termios.TCSADRAIN, original_attr) # 测试 if __name__ == "__main__": try: content = multi_line_input("请输入内容(Ctrl+D结束输入,Ctrl+C终止):\n") print(f"\n输入的原始内容为:\n{repr(content)}") except KeyboardInterrupt: print("\n输入已终止") sys.exit(0)
适用Windows平台
import sys import msvcrt def multi_line_input(prompt: str = "") -> str: buffer = [] if prompt: sys.stdout.write(prompt) sys.stdout.flush() while True: char = msvcrt.getwch() # 处理Ctrl+C终止输入 if ord(char) == 3: raise KeyboardInterrupt # 处理退格 elif char in ("\x7f", "\b"): if buffer: buffer.pop() sys.stdout.write("\b \b") sys.stdout.flush() # 处理Ctrl+D结束输入 elif ord(char) == 4: sys.stdout.write("\n") sys.stdout.flush() return "".join(buffer) # 处理回车换行 elif char == "\r": buffer.append("\n") sys.stdout.write("\n") sys.stdout.flush() # 普通字符存入缓冲区 else: buffer.append(char) sys.stdout.write(char) sys.stdout.flush() # 测试 if __name__ == "__main__": try: content = multi_line_input("请输入内容(Ctrl+D结束输入,Ctrl+C终止):\n") print(f"\n输入的原始内容为:\n{repr(content)}") except KeyboardInterrupt: print("\n输入已终止") sys.exit(0)
效果验证
- 输入过程中敲回车会直接插入换行符,敲退格可以删除包括换行在内的所有已输入字符
- 按
Ctrl+C会直接触发KeyboardInterrupt终止输入流程 - 全程没有使用
sys.stdin.readlines(),完全符合要求
内容的提问来源于stack exchange,提问作者Chen-Y0y0
相关产品推荐
相关产品推荐

