August 25, 2007

用 Python 写了个背单词小工具

注:此“软件”已被作者开为 Google Code 项目 Rewords
背单词关键在于重复,单词能不能背得取决于你看了它多少遍。把一个单词表(wordlist)中的每个 list 分成许多个 section,反复地浏览记忆就能记住。基于此,昨晚我用 Python 写了一个背单词的小工具,暂定名 Rewords 。

#!/usr/bin/python
# Filename: rw.py

import sys

def locate (f, i, n = 1):
  if n == i:
    print f.readline()
    return f
  if f.readline() == "\n":
    return locate(f, i, n+1)
  return locate(f, i, n)

def struct (f, st = []):
  ln = f.readline()[:-1]
  if ln == "":
    return st
  return struct(f, st+[ln])

def conmat (ls, l, tmp = []):
  if len(tmp) == l:
    return [tmp]+conmat(ls, l)
  if len(ls) <= l and tmp == []:     return [ls]   return conmat(ls[1:], l, tmp+[ls[0]]) def inter (st):   '''usage: `Enter`
-
n : next word
p : prev word
d : down to next section
u : up to prev section
: jump to section
l : jump to list '''
  def term (rt, lt = [], n = 0, cur = 'n'):
    def help ():
      print inter.func_doc
      term(rt, lt, n, cur)

    def next ():
      if rt == []:
        term(lt , rt, n, 'n')
      print rt[0]
      term(rt[1:] , lt+[rt[0]], n, 'n')

    def prev ():
      if lt == []:
        term(lt , rt, n, 'p')
      print lt[-1]
      term([lt[-1]]+rt, lt[:-1], n, 'p')

    def down ():
      if n == len(st)-1:
        term(st[0], n=0)
      term(st[n+1], n = n+1)
  
    def up ():
      if n == 0:
        term(st[len(st)-1], n=len(st)-1)
      term(st[n-1], n = n-1)

    def to (p = 1):
      num = (p-1)%len(st)
      term(st[num], n = num)

    def err ():
      print " # unsupported command"
      term(rt, lt, n, cur)

    cmd = sys.stdin.readline()[:-1]
    if cmd == "q": quit()
    if cmd == "h": help()
    elif cmd == "":
      if cur == 'n': next()
      elif cur == 'p': prev()
    elif cmd == "n": next()
    elif cmd == "p": prev()
    elif cmd == "d": down()
    elif cmd == "u": up()
    elif cmd.isdigit(): to(int(cmd))
    elif cmd[0] == 'l' and cmd[1:].isdigit():
      start(int(cmd[1:]))
    else: err()
  term(st[0])

def quit (m = ""):
  if m:
    print m
    sys.exit(1)
  sys.exit(0)

def start (wl = 1):
  '''usage: python rw.py [list] [section]
The wordlist named must be separated by blank lines;
program will start with the [list] or first part of the wordlist;
the each section will contain [section] or 8 words. '''
  inter(conmat(struct(locate( \
    open(sys.argv[1] if len(sys.argv) > 1 \
      else quit(start.func_doc)), wl)), \
    int(sys.argv[3] if len(sys.argv) > 3 else 8)))

print "rw.py - Rewords 0.1a by lichray\n"
start(int(sys.argv[2] if len(sys.argv) > 2 else 1))

程序是自省的,用起来应该没问题。无参数运行 python rw.py 显示帮助。
参数1 是单词表文件名,这个文件需要被空行分解为多个 list,每个 list 的第一行是标题;
参数2 是启动时加载的 list 编号,默认为 1;
参数3 是每个 section 包含的单词数,默认为 8;
进入互交描述后参考帮助,输入 h 命令,回车。
我这儿有一个可用的单词表——Barron SAT 词表,但存在一个小 Bug,不知为什么这个词表只能加载前13个 list,想帮忙的人留个邮箱地址,我把东西都发过去。
另外 locate() 函数还不能处理 readline() 越界的情况,这部分没完成。
最后根据我的代码风格,猜猜看我最近什么语言用的比较多?

3 comments:

LichRay said...

终于知道为什么了... Python 没有尾递归优化,面对数千行的词表早就 C stack overflow 了~`讨厌。

风灵轩 said...

用 dictdlib 这个 module 来写会好玩一点,可以直接读 dictd 的词典...

Elvina said...

Well written article.