Table of Contents
介绍
Anki1
Anki是一个基于间格重复(Spaced Repetition)的字卡软件,同样基于该原理的软件还有商业软件SuperMemo(这个要钱的)和免费软件Mnemosyne。
Anki对SuperMemo的SM2算法予以改进,使其可以根据记忆卡的优先级、紧急程度进行优化调整。SuperMemo的算法已经更新到好多,据Anki作者解释,因为后面的算法比较复杂,而通常用不到,所以就采用了SM2算法。如果你不是很相信这种算法的话,可以使用SuperMemo来比对下。
值得指出的是Anki记忆卡采用HTML语言编写,支持插入图片、音频以及LaTeX公式,这样方便了我们创造出丰富多彩的卡片格式,也是本文使用的前提。
Anki支持多平台客户端,包括PC、安卓、iOS、塞班等,也可以直接登录Ankiweb进行学习。除此之外,注册一个免费账户,便可实现平台之间的同步,不过这种同步不能太过于依赖(作者表示记得考试前几天在手机上修改了卡片,到最后竟然不能同步,郁闷死本人了)。另外有个奇葩的问题,Anki的IOS版本是要收费的,而且很不便宜,其他平台如Android版本竟然免费。据作者解释,这是因为有些合作开发的人提出还是要求来着在Android版本上免费,让我们真心感谢这些合作开发者(跪拜大神)。
星际译王(stardict)
星际译王(StarDict)是一套自由的桌面字典软件。它并不包含字典档,使用者须自行下载配合使用。它可以运行于多种不同的平台,如Linux,Microsoft Windows,FreeBSD及Solaris,并使用GPL授权。
我们这次并不一定用到这个软件,只要用到其命令行下的命令sdcv以及其词典(注意有些词典是破解版)。
步骤
如果平时你使用星际译王查询陌生单词,是否会想将其记下来然后以后再反复的记忆?于是我们就有了将星际译王和Anki联合的想法。
一搜网上,有人已经写了这么的一个插件 StarDict-history-to-Anki ,帮我们实现了这一个功能。但是作为一个审美观念极强的人,我实在不喜欢这个代码实现的纯黑白的卡片,一直想美化它,于是也就有了下文。
通过星际译王查词记录获得词汇
原作者的思路很清晰,StarDict每次关闭后(请注意!要关闭StarDict!!!),StarDict目录下会产生一个history文件记录你这次查询的单词记录,再通过sdcv提取出每个义项的解释,略加修饰既可导入anki中。
原作者初始版本的代码请参考上面链接,我在这里展示已经修饰过的代码。
#!/bin/bash # This is a simple script that research the words in the searching history of StarDict. # # The explanations of each word are saved in a file "~/ankifile" in your $HOME, # which can be loaded later into anki with an option "Fields separated by: Tab". # (when loading "ankifile", remember to check the option "Allow HTML in fields", if your explanations contains html tags) ######## how to install ? ######## # put it in a folder like "~/bin", and make it executable # $ chmod +x dict2anki ####### how to use ? ####### # run it without any arguments in terminal # $ dict2anki # # then a file called ~/ankifile is ready to import into Anki # Note: StarDict creates the history file when it is closed. # Please run dict2anki with StarDict closed. ######## how to change the name/location of the output file ? ######### # check the variable "outputFileName", assign you prefered filename ############ how to add more dicts ? ############ # put a line like the following after the line of "meanings=`sdcv -n \" # -u "dict-name" \ ########### how to find the above "dict-name" ############## # dict names can be found by searhing a word mannuly with sdcv in terminal. # # Here in the following is the output of sdcv after searching hello by "$ sdcv hello" on my PC. # It promotes all my dict names, e.g., "XDICT英汉辞典", "Collins COBUILD V3", "我爱法语-英法词典". # # Found 15 items, similar to hello. # 0)XDICT英汉辞典-->hello # 1)懒虫简明英汉词典-->hello # 2)朗道英汉字典5.0-->hello # 3)Merriam-Webster Collegiate® Dictionary-->hello # 4)XDICT英汉辞典-->hello # 5)CMU American English spelling-->hello # 6)Collins COBUILD V3-->hello # 7)The CMU Pronouncing Dictionary-->hello # 8)Longman Dictionary of Contemporary English-->hello # 9)美国传统词典[双解]-->hello # 10)stardict1.3英汉辞典-->hello # 11)Longman Dictionary of Contemporary English (4th Ed)-->hello # 12)Merrian Webster 10th dictionary-->hello # 13)我爱法语-法英词典-->hello # 14)我爱法语-英法词典-->hello # Your choice[-1 to abort]: # (ctrl-c to abort also) ############# here we go ############# outputFileName=~/ankifile # if there is a searching history file "~/.stardict/history" if [ -f ~/.stardict/history ] then while read line do meanings=`sdcv -n \ -u "21世纪英汉汉英双向词典" \ -u "朗道英汉字典5.0" \ -u "牛津英汉双解美化版" \ -u "CDICT5英汉辞典" \ -u "英文字根字典" \ "$line" | sed '/Nothing similar to/d;/Found/d' | perl ~/.beautify.pl` # 搜寻媒体文件 find /media/学习与工作/Software/SoftwareOfStudy/Dictionary/Lingoes/Translator2/speech/M-W\ English/voice/ -name $line.wav -exec cp {} ~/Anki/cxp/collection.media/ \; if [ -n "$meanings" ]; then # the output file is named as "~/ankifile" (in $HOME folder) echo -e "<div id=\"word\">$line</div>\t<div class=\"vd_longman\">[sound:$line.mp3]</div>\t<div class=\"vd_mw\">[sound:$line.wav]</div>\t$meanings" >> $outputFileName fi # load searching history from "~/.stardict/history" done < ~/.stardict/history # move stardict history file to home folder mv ~/.stardict/history ~/ echo "Done, saved in $outputFileName" else echo "There is no ~/.stardict/history" fi exit
为了让大家理解,解释项也贴了进去。下面就是关键的代码,即.beautiful.pl代码。
标记
关于词典的美化,曾经走了歪路。就是想把原词典的每个义项例句单独提取出来,但这种提取方法真的是太复杂了,而且词典格式本来就有些地方不是很标准。
然后更换了思路,对其中的关键特征进行标记。每个词典都是一个列表,每列都有一个单独的class属性(对html有一丁点的认识的都应该知道,本文作者只是一只菜鸟都理解了。。。啊哈哈哈哈),用以区分义项、例句和其他。
标记解释:k keys 关键词;主项; c categery 种类;形容词动词等; m meaning 解释项; e example 词组或例句; o other 其他。
具体的代码如下:
#!/use/bin/perl use 5.010; # 判断文件打开 #if (! open FILE, "dict2anki.tmp") { # die "Cannot open file: $!"; # exit; #} # 一次性读取所有数据 @all_data = <>; # 获取词典解释起止位置,以哈希存储 $i=0; foreach $all (@all_data) { if ( $all =~ /^(-->朗道)/ ) { push (@cidian, $i); $hdic{"$i"}="langdao"; } if ( $all =~ /^(-->牛津)/ ) { push (@cidian, $i); $hdic{"$i"}="niujin"; } if ( $all =~ /^(-->CDICT)/ ) { push (@cidian, $i); $hdic{"$i"}="cdict"; } if ( $all =~ /^(-->21世纪)/ ) { push (@cidian, $i); $hdic{"$i"}="sj21"; } if ( $all =~ /^(-->英文字根)/ ) { push (@cidian, $i); $hdic{"$i"}="zigen"; } $i++; } $hdic{$i} = "end"; push (@cidian, $i); #foreach $key (sort keys %hdic){ # $value = $hdic{$key}; # print "$key => $value \n"; #} # 得到由小到大的字典行数排列 my @keys = sort { $a <=> $b } keys %hdic; # print "@keys \n"; # 得到每个字典的解释 landao,niujin,sj21,cdict,zigen分别用@+字典简写访问 $len = @keys; for ($i=0; $i<$len; $i++){ $n1 = $hdic{@keys[$i]}; @$n1 = @all_data[($keys[$i]+3)..($keys[$i+1]-2)]; } # 修改21世纪英汉汉英大辞典的格式 ## 对一些不符合规范的格式调整 将<<>>顶头写 $len = @sj21; for ($i=0; $i<$len; $i++) { if (@sj21[$i] ~~ /<<.*>>/) { push (@da , $i ); #获取含有<<>>解释项所在数组列 if($`) { @sj21[$i-1] = @sj21[$i-1].$`; @sj21[$i] = $&.$'; } } } ## 进行标注 << k keys 关键词;主项; c categery 种类;形容词动词等; m meaning 解释项; e example 词组或例句; o other 其他; chomp @sj21[0]; chomp @sj21[1]; @sj21[0] = "<div><ul id=\"sj21\"><li class=\"k\">".@sj21[0]."</li>"; @sj21[1] = "<li class=\"o\">".@sj21[1]."</li>"; $len = @sj21; for ($i=2; $i<$len; $i++) { chomp $sj21[$i]; if ($sj21[$i] ~~ /<<.*>>/) { $sj21[$i] = "<li class=\"c\">".$sj21[$i]."</li>"; } elsif ($sj21[$i] ~~ /( *^[0-9])|( *^[a-z]\.)/) { $sj21[$i] = "<li class=\"m\">".$sj21[$i]."</li>"; } else { $sj21[$i] = "<li class=\"e\">".$sj21[$i]."</li>"; } } foreach $sj21 (@sj21) { $sj21 =~ s/\n//g; #去掉换行符等; $sj21 =~ s/\r//g; #去掉换行符等; } push (@sj21, "</ul></div>"); # 修改朗道英汉 ## 进行标注 << k keys 关键词;主项; c categery 种类;形容词动词等; m meaning 解释项; e example 词组或例句; o other 其他; chomp @langdao[0]; @langdao[0] = "<div><ul id=\"langdao\"><li class=\"o\">".@langdao[0]."</li>"; $len = @langdao; for ($i=1; $i<$len; $i++) { chomp $langdao[$i]; if ($langdao[$i] ~~ / *[a-z]+\./) { $langdao[$i] = "<li class=\"m\">".$langdao[$i]."</li>"; } elsif ($langdao[$i] ~~ / *(相关词组)/) { $langdao[$i] = "<li class=\"c\">".$langdao[$i]."</li>"; } else { $langdao[$i] = "<li class=\"e\">".$langdao[$i]."</li>"; } } foreach $langdao (@langdao) { $langdao =~ s/\n//g; #去掉换行符等; $langdao =~ s/\r//g; #去掉换行符等; } push (@langdao, "</ul></div>"); # 修改CDICT ## 进行标注 << k keys 关键词;主项; c categery 种类;形容词动词等; m meaning 解释项; e example 词组或例句; o other 其他; chomp @cdict[0]; chomp @cdict[1]; @cdict[0] = "<div><ul id=\"cdict\"><li class=\"o\">".@cdict[0]."</li>"; @cdict[1] = "<li class=\"o\">".@cdict[1]."</li>"; $len = @cdict; for ($i=2; $i<$len; $i++) { chomp $cdict[$i]; if ($cdict[$i] ~~ / *^<<.*>>/) { $cdict[$i] = "<li class=\"c\">".$cdict[$i]."</li>"; } elsif ($cdict[$i] ~~ /( *^[0-9])|((( *)|(\t)|(\n)|(\r))[a-z]\.)/) { $cdict[$i] = "<li class=\"m\">".$cdict[$i]."</li>"; } elsif ($cdict[$i] ~~ / *^\[/) { $cdict[$i] = "<li class=\"o\">".$cdict[$i]."</li>"; } else { $cdict[$i] = "<li class=\"e\">".$cdict[$i]."</li>"; } } foreach $cdict (@cdict) { $cdict =~ s/\n//g; #去掉换行符等; $cdict =~ s/\r//g; #去掉换行符等; } push (@cdict, "</ul></div>"); # 修改niujin ## 进行标注 << k keys 关键词;主项; c categery 种类;形容词动词等; m meaning 解释项; e example 词组或例句; o other 其他; chomp @niujin[0]; @niujin[0] = "<div><ul id=\"niujin\"><li class=\"o\">".@niujin[0]."</li>"; $len = @niujin; for ($i=1; $i<$len; $i++) { chomp $niujin[$i]; if ($niujin[$i] ~~ / *^[a-z]+/) { $niujin[$i] = "<li class=\"c\">".$niujin[$i]."</li>"; } elsif ($niujin[$i] ~~ /( *^[0-9])|( *^\([a-z]+\))/) { $niujin[$i] = "<li class=\"m\">".$niujin[$i]."</li>"; } else { $niujin[$i] = "<li class=\"e\">".$niujin[$i]."</li>"; } } foreach $niujin (@niujin) { $niujin =~ s/\n//g; #去掉换行符等; $niujin =~ s/\r//g; #去掉换行符等; } push (@niujin, "</ul></div>"); # 修改英文字根词典 ## 进行标注 << k keys 关键词;主项; c categery 种类;形容词动词等; m meaning 解释项; e example 词组或例句; o other 其他; chomp @zigen[0]; @zigen[0] = "<div><ul id=\"zigen\"><li class=\"o\">".@zigen[0]."</li>"; $len = @zigen; for ($i=1; $i<$len; $i++) { chomp $zigen[$i]; if ($zigen[$i] ~~ / *[a-z]+\./) { $zigen[$i] = "<li class=\"m\">".$zigen[$i]."</li>"; } elsif ($zigen[$i] ~~ / *(根)/) { $zigen[$i] = "<li class=\"m\">".$zigen[$i]."</li>"; } else { $zigen[$i] = "<li class=\"e\">".$zigen[$i]."</li>"; } } foreach $zigen (@zigen) { $zigen =~ s/\n//g; #去掉换行符等; $zigen =~ s/\r//g; #去掉换行符等; } push (@zigen, "</ul></div>"); # 综合所有修饰结果 @modified = ("\t",@sj21,"\t" ,@langdao,"\t" ,@niujin,"\t" ,@cdict,"\t",@zigen); print "@modified";
如此可以对每个义项进行标记,然后分别做不同处理。(词典暂时只有"21世纪英汉汉英双向词典","朗道英汉字典5.0","牛津英汉双解美化版","CDICT5英汉辞典","英文字根字典";个人觉得够了,谁会背单词看那么多词典。。。不过可添加一本例句词典,不知大家有啥建议)
Anki的修饰
经过上面的处理,我们在家目录获得了ankifile文件,这个便可以导入Anki程序中。请注意导入时,第1列是单词,第2、3列是预留出来的读音文件,第4、5、6、7、8既是上述的词典顺序(词典是分开的)。
我这里给大家提供一个配色模板,个人觉得还不错(请原谅我无耻的借用了 欧陆词典 的配色方案)。
卡片格式刷中的代码
*,ul,li {padding: 0; margin: 0; list-style-type: none;}
.card { font-family: arial; font-size: 20px; text-align: left; color: black; background-color: #F8FBEF; line-height: 110%; }
.k { color: #FF0000; font-size: 18px; }
.o { color: #FFCC66; }
.c { color: #008000; }
.m { color: #0000FF;#0000CD; }
.b { color: #000000; }
.e { color: #9400D3 ;#8A2BE2; text-indent: 3%; list-style-positon: inside; }
正面模板为:
<div style='font-family: Arial; font-size: 22px;text-align: center;'></div><br>
背面模板为:
<div style='font-family: Arial; font-size: 20px;text-align:center;'></div>
<hr id=answer> <div style='text-align:left;font-family: Arial; font-size: 16px;color:#FF00FF;text-indent:0em'>笔记:</div>
<div style='text-align:left;font-family: Arial; font-size: 16px;text-indent:1.5em;color:#000000;'></div><br>
<div style='text-align:left;font-family: Arial; font-size: 14px;color:#FF0000;text-indent:0em;text-align: center'>21世纪英汉汉英双向词典</div><br> <div style='font-family: Arial; font-size: 16px;'></div><br>
<div style='border:1px solid #FF0000;text-align:left;font-family: Arial; font-size: 14px;color:#FF0000;text-indent:0em;text-align: center;'>朗道英汉字典</div><br> <div style='font-family: Arial; font-size: 16px;'></div><br>
<div style='border:1px solid #FF0000;text-align:left;font-family: Arial; font-size: 14px;color:#FF0000;text-indent:0em;text-align: center;'>英语字根字典</div><br> <div style='font-family: Arial; font-size: 16px;'></div><br>
<div style='border:1px solid #FF0000;text-align:left;font-family: Arial; font-size: 14px;color:#FF0000;text-indent:0em;text-align: center;'>牛津英汉双解美化版</div><br> <div style='font-family: Arial; font-size: 16px;'></div><br>
<div style='border:1px solid #FF0000;text-align:left;font-family: Arial; font-size: 14px;color:#FF0000;text-indent:0em;text-align: center'>CDICT5英汉辞典</div><br> <div style='font-family: Arial; font-size: 16px;'></div><br>
<div style='font-family: Arial; font-size: 18px;'></div><br>
<div style='font-family: Arial; font-size: 20px;'></div><br>
<div style='border:1px solid #000000;background-color:#FFFFFF;text-align:left;font-family: Arial; font-size: 15px;color:#0489B1;'>标签: </div>
总结
限于个人水平,暂时只能将美化做到这种地步。主要有一个问题就是,如果查询单词中出现了词组,那么配色中的第一二三列会出现配色方案的混乱(会代码的可以从我写的perl脚本中知道这种错误出现的原因),希望高手能够同我一起解决。
此外我还附上完整版的 dict2anki .beautify.pl 下载地址,请点击名称下载既可。.beautiful.pl放在家目录即可,其会隐藏,主要是为了不干扰家目录的文件。