您尚未登录。

#1 2017-01-22 14:43:17

alexxey
会员
注册时间: 2016-12-28
帖子: 73

python如何清理stdin的残留内容?

定义以下函数,一次读取一个汉字(3个字节):

def get3char():
	ch = ''
	fd = sys.stdin.fileno()
	old_settings = termios.tcgetattr(fd)
	try:
		tty.setraw(sys.stdin.fileno())
		while True:
			tmp = sys.stdin.read(1)
			if tmp == '\x1b': # ESC
				return '\x1b'
			elif tmp == '\r': # RETURN
				return '\r'
			elif tmp.isalnum():
				pass
			else:
				ch += tmp
			if len(ch) == 3: break

	finally:
		termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)

	return ch

问题是:输入一个4字节字符如 ? (\xf0\xa0\x9c\x8e) 时,最后一个字节 \x8e 会残留在缓冲区内。造成下次输入正常3字节汉字时乱码。
如何将其清理掉?

谢谢!

离线

#2 2017-01-22 17:12:19

依云
会员
所在地: a.k.a. 百合仙子
注册时间: 2011-08-21
帖子: 8,917
个人网站

Re: python如何清理stdin的残留内容?

你为什么要 if len(ch) == 3: break?
你换 Python 3 应该就好了。

离线

#3 2017-01-22 17:30:44

alexxey
会员
注册时间: 2016-12-28
帖子: 73

Re: python如何清理stdin的残留内容?

非常感谢回答。我的实际意图是制作一个中文打字练习/测速程序,使用 get3char() 一次输入一个汉字。
如果不加 if len(ch) == 3: break,输入完第一个中文字符后无法自动返回之,会一直读取。

根据个人肤浅的了解,使用 Python 3 应该在中文字符串处理时比较方便,对于这个具体问题有无助益?

谢谢!

目前的实际代码是这样的:

#!/usr/bin/python
# -*- coding: utf-8 -*-

import os
import sys
import tty
import time
import termios
from textwrap import wrap


def extract_char(txt, i):
	return txt[i*3-3:i*3]

def get3char():
	ch = ''
	fd = sys.stdin.fileno()
	old_settings = termios.tcgetattr(fd)
	try:
		tty.setraw(sys.stdin.fileno())
		while True:
			tmp = sys.stdin.read(1)
			if tmp == '\x1b': # ESC
				return '\x1b'
			elif tmp == '\r': # RETURN
				return '\r'
			elif tmp.isalnum():
				pass
			else:
				ch += tmp
				
			if len(ch) >= 3:
				break
			
	finally:
		termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
	
	return ch[:3]

def do_drill(script):
	global count, line_number
	count += 1
	if count%2 != 0 and count > 1:
		raw_input("\nPress RETURN to continue")
		sys.stdout.write("\033c")
		sys.stdout.flush()
	elif count%2 != 0:
		sys.stdout.write("\033c")
		sys.stdout.flush()

	script = script.rstrip()
	length_of_script = len(script)/3.
	if not length_of_script.is_integer():
		print "Script contains alphanumeric text."
		line_number += 1
		return 'passed'
	else:
		length_of_script = int(length_of_script)

	print "  "
	print "  "
	print " ", script
	sys.stdout.write("  ")
	sys.stdout.flush()

	typed = 0
	mistyped = 0
	for i in range(1, length_of_script+1):
		char_typed = get3char()
		if i == 1:
			time_start = time.time()

		if char_typed == '\x1b':
			print "Aborted."
			sys.exit()
		elif char_typed == '\r':
			break
		elif char_typed != extract_char(script, i):
			sys.stdout.write('\x1b[6;37;41m'+char_typed+'\x1b[0m')
			sys.stdout.flush()
			mistyped += 1
			typed += 1
		else:
			sys.stdout.write(char_typed)
			sys.stdout.flush()
			typed += 1

	
	time_stop = time.time()
	elapsed_time = round(time_stop-time_start, 2)+0.01
	speed = round(60*(typed-1)/elapsed_time, 2)

	if speed < 0 or speed > 999:
		speed = "N/A"
	else:
		speed = str(speed)+'cpm'

	print ' '
	print ' '
	print '  Line: '+str(line_number)+', Elapsed: '+str(elapsed_time)+'s, Speed: '+speed
	print '  Expected: '+str(length_of_script)+', Typed: '+str(typed)+', Mistyped: '+str(mistyped)
	
	if mistyped == 0:
		line_number += 1
		return 'passed'
	else:
		return 'meh'

def main():
	in_fname = sys.argv[1] if len(sys.argv) > 1 else 'mydrill'
	chunk_size = int(sys.argv[2]) if len(sys.argv) > 2 else 35

	f = open(in_fname)
	txt = f.read()
	f.close()

	list_of_drill_script = wrap(txt, chunk_size*3)

	global count, line_number
	count = 0
	line_number = 1

	for each_line in list_of_drill_script:
		while True:
			status = do_drill(each_line)
			if status == 'passed': break

if __name__ == "__main__":
	main()

最近编辑记录 alexxey (2017-01-22 17:38:19)

离线

#4 2017-01-22 18:06:26

依云
会员
所在地: a.k.a. 百合仙子
注册时间: 2011-08-21
帖子: 8,917
个人网站

Re: python如何清理stdin的残留内容?

你试试 codecs.open 把流弄成 unicode 的吧。汉字并不都是三个字节的。
你要自己实现读取一个 (Unicode)字符的话,UTF-8 编码是很有规律的,你去维基百科看一下,然后自己写一个读取一个字符的函数吧。

Python 3 里的 str 实际上对应于 Python 2 里的 unicode 类型。它们用来处理字符比较方便。

最近编辑记录 依云 (2017-01-22 18:07:44)

离线

#5 2017-01-22 19:00:23

alexxey
会员
注册时间: 2016-12-28
帖子: 73

Re: python如何清理stdin的残留内容?

非常感谢指出正确方向,我会进一步学习。目前这个办法确实太简陋了。
实际上我是看到这位网友制作的“linux终端窗口下的中文打字练习”
http://blog.chinaunix.net/xmlrpc.php?r= … id=4025789
实际使用起来发现限制较多,个人又不会修改c代码,于是打算用python再实现一个类似的。

-----------------------
http://www.i18nguy.com/unicode/supplementary-test.html

离线

页脚