论坛首页 Ruby版 ruby

Ruby Quiz

浏览 11003 次
锁定老贴子 主题:Ruby Quiz
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
最后更新时间:2006-04-12
刚刚在看Ruby Quiz,发现有些解法真的很巧妙

Quiz 1: MadLibs

简单的模板,假设有一句话

I had a ((an adjective)) sandwich for lunch today. It dripped all
over my ((a body part)) and ((a noun)).

程序应该拿这些((..))中间的词组问你:

Give me an adjective?
Give me a body part?
Give me a noun?

你回答以后,程序用你的答案代替相应的问题

譬如你分别回答smelly、big toe 、 bathtub

程序打印:

I had a smelly sandwich for lunch today. It dripped all
over my big toe and bathtub.

有时候你可能要重用问题,则可以给问题一个名字。例如:

Our favorite language is ((gem:a gemstone)). We think ((gem)) is
better than ((a gemstone)).

这里第一个((gem:a gemstone))给出了一个名字gem,而第二个((gem))直接用gem这个名字就可以复用第一个问题的答案了。

因此,程序只需要问你两个问题:
Give me a gemstone?
Give me a gemstone?

如果你回答
Ruby、Emerald

结果就是
Our favorite language is Ruby. We think Ruby is better than
Emerald.
   
最后更新时间:2006-04-12
我自己做的答案按部就班,和他书上的第二个差不多,但是看起来还是比较Java。书上给的第三个答案比较有意思,一共6行代码



[code:1]1 keys=Hash.new { |h, k|
     2 puts "Give me #{k.sub(/\A([^:]+):/, "")}:"
     3 h[$1]=$stdin.gets.chomp
4 }
5 puts "", $*[0].split(".")[0].gsub("_", " "),
6 IO.read($*[0]).gsub(/\(\(([^)]+)\)\)/) { keys[$1] }[/code:1]

实际上,第4行的}不能算有效代码,而第5行是打印一个题头,真正有效的代码是4行
   
0 请登录后投票
最后更新时间:2006-04-12
第5行开始的puts就是打印,它可以带n个参数,第一个参数""没啥用,第二个参数


[code:1] $*[0].split(".")[0].gsub("_", " ")[/code:1]
中的$*实际上就是ARGV,$*[0]就是第0个参数split(".")把文件名和后缀名分开,然后gsub替换"_"为"",例如你的文件名为read_me.txt,就变成了read me.这句话就是打印一个题头。


[code:1]IO.read($*[0]).gsub(/\(\(([^)]+)\)\)/) { keys[$1] }[/code:1]

首先read($*[0])就是把命令行的第0个参数作为文件名,并把它的内容读入到一个字符串。gsub是全局替换,这里有两个参数

[code:1]/\(\(([^)]+)\)\)/[/code:1] 是它的正则表达式参数
[code:1]keys[$1][/code:1]是它的block参数

意思就是用正则表达式匹配,并每次用block返回的值进行替换。

[code:1]/\(\(([^)]+)\)\)/[/code:1] 的左边\(\(和右边\)\),分别匹配题意中的((..)),而([^)]+)则是一个group,匹配任何非)的字符,每次匹配成功((...))中间的内容变成$1,就是第一个group。

引用
keys[$1]


把$1作为关键字,去取它的值

现在看看

[code:1]1keys=Hash.new { |h, k|
2      puts "Give me #{k.sub(/\A([^:]+):/, "")}:"
3      h[$1]=$stdin.gets.chomp
4} [/code:1]

Ruby的Hash构造函数有三种形式,这种方式是Hash.new block。此时,如果你用一个已经在Hash中存在的关键字去取值,那么就直接返回值,如果这个关键字不存在,那么就用hash本身和你需要的关键字调用这个block.

现在可以看看,如果没有答案的重用,例如

引用
I had a ((an adjective)) sandwich for lunch today. It dripped all
over my ((a body part)) and ((a noun)).



第一次用an adjective变成$1到keys去取值,没有找到,调用这个block,而且第2行的/\A([^:]+):/ 没有匹配,因此$1还是等于an adjective,结果就是屏幕提问
引用
Give me an adjective?

keys["an adjective"] = 你回答的答案



如果有可以重用的答案,例如:
引用
Our favorite language is ((gem:a gemstone)). We think ((gem)) is
better than ((a gemstone)).


第一次,$1="gem:a gemstone",显然无法在keys里面找到,但是第2行的/\A([^:]+):/匹配gem:,并且把$1="gem",因此,屏幕提示

引用
Give me a gemstone?
keys["gem"] = 你回答的答案


第二次,$1="gem",我们上一次已经在keys这个hashmap里面有了这个值,因此整个block就不执行,屏幕不需要提示,答案也可以重用了
   
0 请登录后投票
最后更新时间:2006-04-12
这本书确实很不错
很多问题只需跳一跳自己也可以解
然后再看看解答
真的爽快

有时候读源码相对高度就会比较高
这个就比较好
   
0 请登录后投票
最后更新时间:2006-04-12
我现在也在翻这本书,感觉真的不错。相对而言,算是比较高阶的了!很多的Quiz,在自己实际的implement以后,才发现别人的更高,实现的更加优雅!
也知道了自己的差距又多远...
   
0 请登录后投票
最后更新时间:2006-04-12
怎么感觉又想起了perl.
问题是,代码写成这样,简洁是简洁了,但是一般人猛一看,还真不知道它是干嘛的.想改个东西也不好下手.
   
0 请登录后投票
最后更新时间:2006-04-12
可能是$*和正则表达式给搞的吧


这个解答从某些方面来说并不是很好,譬如可读性方面,可重用性方面,只不过设计巧妙,充分利用了Block的优势
   
0 请登录后投票
最后更新时间:2006-04-12
我同事的Javascript实现

[code:1]<script>
var str = "I had a ((gem:an adjective)) sandwich for lunch today. It dripped all over my ((gem)) and ((a noun)). ";
/**** Start ****/
var h = {};// it's a Hash
document.write(str.replace(/\(\(([^)]+)\)\)/ig,function($1,$2){
var k = $2.split(":")[0],o=$2.split(":")[1]||k;
return "<b style='color:red'>"+ (h[k]||(h[k]=prompt("Give me "+o,"")))+"</b>";
}));
</script>[/code:1]
   
0 请登录后投票
最后更新时间:2006-04-13
有没有类似的quiz书,在关于好的OOP方面的书推荐一下?
   
0 请登录后投票
最后更新时间:2006-04-13
脚本语言可以写出十分灵活的代码。可它比较难懂
   
0 请登录后投票
论坛首页 Ruby版 ruby

跳转论坛:
JavaEye推荐