ruby
http://wiki.yepn.net/ruby
Ruby
没有什么特别的原因开学学习Ruby,只是从兴趣出发
Programming Ruby 2nd Edition
特殊变量
$! 最近一次的错误信息 $@ 错误产生的位置 $_ gets最近读的字符串 $. 解释器最近读的行数(line number) $& 最近一次与正则表达式匹配的字符串 $~ 作为子表达式组的最近一次匹配 $n 最近匹配的第n个子表达式(和$~[n]一样) $= 是否区别大小写的标志 $/ 输入记录分隔符 $\ 输出记录分隔符 $0 Ruby脚本的文件名 $* 命令行参数 $$ 解释器进程ID $? 最近一次执行的子进程退出状态
Enumerable
分组迭代
以前我们所介绍的迭代都是每次迭代一个元素,如果我们想要迭代一个组的时候,我们可以使用each_slice require 'enumerator' arr = [1,2,3,4,5,6,7,8,9,10] arr.each_slice(3) do |triple| puts triple.join(",") end #这里传入的3,也就意味着,每次传进去三个元素. # Output: # 1,2,3 # 4,5,6 # 7,8,9 # 10
partition 方法
简而言之,partition 方法就是用来分组的,也就是说,它可以将一个数组根据一定的规则分为不同的组 nums = [1, 2, 3, 4, 5, 6, 7, 8, 9] odd_even = nums.partition {|x| x % 2 == 1 } # [[1,3,5,7,9],[2,3,4,6,8]] #分组后产生多维数组 under5 = nums.partition {|x| x < 5 } # [[1,2,3,4],[5,6,7,8,9]] squares = nums.partition {|x| Math.sqrt(x).to_i**2 == x } # [[1,4,9],[2,3,5,6,7,8]]
使用量词符
nums = [1,3,5,8,9] # 这些元素有一个偶数吗? flag1 = nums.any? {|x| x % 2 == 0 } # true #这些元素都是偶数吗? flag2 = nums.all? {|x| x % 2 == 0 } # false
words得到数组里面最长的那个元素
words = %w[ alpha beta gamma delta epsilon eta theta ] longest_word=words.inject do |best,w| w.length > best.length ? w : best end puts longest_word
Range
转化为数组 很简单,to_a方法搞定: r = 3..12 arr = r.to_a # [3,4,5,6,7,8,9,10,11,12] digits = 0..9 digits.include?(5) -> true digits.min -> 0 digits.max -> 9 digits.reject {|i| i < 5 } -> [5, 6, 7, 8, 9] digits.each {|digit| dial(digit) } -> 0..9 ('a'..'z').to_a.each{|i| puts i} #显示a到z的字符串 r1 = 3..6 r2 = 3...6 #....不包含上线6 r1a, r1b = r1.first, r1.last # 3, 6 r1c, r1d = r1.begin, r1.end # 3, 6 r2a, r2b = r2.begin, r2.end # 3, 6 (注意:不是3和5) r1 = "7".."9" r2 = "7".."10" r1.each {|x| puts x } # 打印出7,8,9 r2.each {|x| puts x } # 未打印任何东西 ##为什么会出现这样的情况?这是因为这里都是字符串,由于r1中,"7"比"9"小 所以,它是个合理的Range;而表达式r2中,"7"比"10"大,下限大于了上限,就不合理了。 r1 = 23456..34567 x = 14142 y = 31416 r1.include?(x) # false r1.include?(y) # true
迭代器
3.times { print "X " } 1.upto(5) {|i| print i, " " } 99.downto(95) {|i| print i, " " } 50.step(80, 5) {|i| print i, " " } #50至80之间步长5
数字
?a -> 97 #ASCII值
读取文件
f=File.open("testfile") f.each{|line| puts line} f.close
Reading
line=gets #从键盘输入负值给line print line #打印line
Hash
由一个数组来创建hash
array = [2, 3, 4, 5, 6, 7] hash = Hash[*array] # hash is now: {2=>3, 4=>5, 6=>7}
合并两个散列
ruby能够使用merge(别名update)方法,来合并两个hash,如果他们中的健有相同的话,一个将会被删除 dict = {"base"=>"foundation", "pedestal"=>"base"} added = {"base"=>"non-acid", "salt"=>"NaCl"} new_dict = dict.merge(added) # {"base"=>"non-acid", "pedestal"=>"base", "salt"=>"NaCl"} merge还可以使用block来处理,两个健有冲突的hash的合并, 我们下面的代码是假设我们有两个冲突的健的话,我们选择值较小的那个键值对 dict = {"base"=>"foundation", "pedestal"=>"base"} added = {"base"=>"non-acid", "salt"=>"NaCl"} new_dict = dict.merge(added) {|key,old,new| old < new ? old : new } # {"salt"=>"NaCl", "pedestal"=>"base", "base"=>"foundation"}
select(别名finad_all)将会返回所有符合条件的键值对
names.select {|k,v| v=="tucker" } # [["joe", "tucker"], ["jane", "tucker"]] names.find_all {|k,v| k.count("r")>0} # [["mary", "SMITH"], ["fred", "jones"]]
根据条件选择键值对
Hash类混入了Enumerable模块,因此你能够使用detect(find),select,(find_all),grep,min,max,和reject这些方法.
detect (别名find)得到一个单独的键值对:names = {"fred"=>"jones","jane"=>"tucker", "joe"=>"tucker","mary"=>"SMITH"} # 得到一个tucker names.detect {|k,v| v=="tucker" } # ["joe","tucker"] # 得到一个大写的 names.find {|k,v| v==v.upcase } # ["mary", "SMITH"]
只想把值或者健转换成数组,可以使用keys或者values 你还可以基于一个键序列,来将他们所对应的值转换换成数组
h.keys # ["a","b"] h.values # [1,2] h = {1=>"one",2=>"two",3=>"three",4=>"four","cinco"=>"five"} h.values_at(3,"cinco",4) # ["three","five","four"] h.values_at(1,3) # ["one","three"]
你还能使用empty? 方法来测试一个hash是否为空,length来得到一个hash的大小
a.empty? # false a.length # 2
检测一个健或者值是否属于一个hash
我们能够使用has_key?或者它的任意一个别名,include?, key?, 和member?来测试一个key是否属于一个hash a = {"a"=>1,"b"=>2} a.has_key? "c" # false a.include? "a" # true a.key? 2 # false a.member? "b" # true
invert
a = {"fred"=>"555-1122","jane"=>"555-7779"} b = a.invert #交换hash表中的key和value b["555-7779"] # "jane" 注意这里有一个问题,那就是值有可能是重复的,这时如果你使用invert的话,它将会删除掉一个重复的键值对 a = {"fred"=>"555-7779","jane"=>"555-7779"} b = a.invert puts b["555-7779"] # "jane"
迭代hash中的key或value
{"a"=>3,"b"=>2}.each_key do |key| print "key = #{key};" # Prints: key = a; key = b; end {"a"=>3,"b"=>2}.each_value do |value| print "val = #{value};" # Prints: val = 3; val = 2; end
迭代一个hash
我们能够使用each方法来做这个,它还有each_key, each_pair和 each_value方法,其中each_pair是each方法的别名 {"a"=>3,"b"=>2}.each do |key, val| print val, " from ", key, "; " # 3 from a; 2 from b; end {"a"=>3,"b"=>2}.each{|key,val|puts "#{val} from #{key}"}
删除的话我们能够使用 clear, delete, delete_if, reject, reject!, 和shift 这些方法都能做到。 clear 将会把一个hash清空.shift则将会删除掉最前面的一个键值对
存取或者加一个键值对
hash也有像数组一样的[]和[]=方法,还有一个store,它是[]=方法的别名 a = {} a["flat"] = 3 # {"flat"=>3} a.[]=("curved",2) # {"flat"=>3,"curved"=>2} a.store("angled",5) # {"flat"=>3,"curved"=>2,"angled"=>5} puts a
histogram = Hash.new() #新建一个Hash表 histogram['key1'] -> 0 histogram['key1'] = histogram['key1'] + 1 histogram['key1'] -> 1 histogram.default = "hello" #没有定义的key会返回hello
Array
数组的交叉
a = [1, 2, 3, 4] b = ["a", "b", "c", "d"] c = a.zip(b) # c is now [[1,"a"], [2,"b"], [3,"c"], [4,"d"]] # Use flatten if you want to eliminate the nesting d = c.flatten # d is now [1, "a", 2, "b", 3, "c", 4, "d"]
uniq
移除掉重复的元素 breakfast = %w[spam spam eggs ham eggs spam] lunch = breakfast.uniq # ["spam","eggs","ham"] breakfast.uniq! # breakfast has changed now
join
将数组转换成字符串 been_there = ["Veni", "vidi", "vici."] journal = been_there.join(", ") # "Veni, vidi, vici." journal.class # String letters = ["Phi","Mu","Alpha"] musicians = letters.join(" ") # "Phi Mu Alpha" people = ["Bob","Carol","Ted","Alice"] movie = people * " and " # movie is now "Bob and Carol and Ted and Alice"
each_with_index 方法的block将会多出一个index参数
x = ["alpha", "beta", "gamma"] x.each_with_index do |x,i| puts "Element #{i} is #{x}" end
reverse_each
words = %w(Son I am able she said) str = "" words.reverse_each { |w| str += "#{w} "} # str is now "said she able am I Son "
clear方法将会删除一个数组中的所有元素。
shift和pop方法,也能删除数组中的元素
x = [1, 2, 3, 4, 5] x.pop # Delete the last element # x is now [1, 2, 3, 4] x.shift # Delete the first element # x is now [2, 3, 4]
delete
我们还能使用delete方法来删除一个指定的元素 b = %w(spam spam bacon spam eggs ham spam) b.delete("spam") # Returns "spam" # b is now ["bacon", "eggs", "ham"] b.delete("caviar") # Returns nil delete还能跟上一个block,block的意思就是如果找不到那个元素就会返回block c = ["alpha", "beta", "gamma", "delta"] c.delete("delta") { "Nonexistent" } # Returns "delta" (block is never evaulated) c.delete("omega") { "Nonexistent" } # Returns "Nonexistent"
delete_at
我们能够使用delete_at方法来删除一个指定位置的元素 a = [10, 12, 14, 16, 18] a.delete_at(3) # 删除 第三个元素(从0开始) Returns 16 # a is now [10, 12, 14, 18] a.delete_at(9) # Returns nil (out of range)
compact
a = [1, 2, nil, 3, nil, 4, 5] b = a.compact # [1, 2, 3, 4, 5] #除去数组中的nil a.compact! # a is now [1, 2, 3, 4, 5]
rand
将一个数组随机显示,也就是打乱掉 我们可以使用kernel的rand方法 x = [1, 2, 3, 4, 5] x.sort_by{rand} #[2, 3, 1, 4, 5]
array并没有定义异或操作,可是我们能够自己定义异或操作
class Array def ^(other) (self | other) - (self & other) end end x = [1, 2, 3, 4, 5] y = [3, 4, 5, 6, 7] z = x ^ y # [1, 2, 6, 7]
grep
grep方法调用===方法来匹配数组中的每一个元素与他自己所带的参数 由于是使用===方法,因此grep方法的参数不需要是正则表达式 a = %w[January February March April May] a.grep(/ary/) # ["January, "February"] b = [1, 20, 5, 7, 13, 33, 15, 28] b.grep(12..24) # [20, 13, 15] 如果使用它的block版本的话,那就更灵活,这样可以再次处理所匹配的元素 # Continuing above example... # Let's store the string lengths a.grep(/ary/) {|m| m.length} # [7, 8] # Let's square each value b.grep(12..24) {|n| n*n} # {400, 169, 225}
sort
words = %w(the quick brown fox) list = words.sort # ["brown", "fox", "quick", "the"] #数组内部排序函数 puts list.to_s # Or sort in place: words.sort! # ["brown", "fox", "quick", "the"] sort方法假设数组里面没一个元素都是可比较的 因此比如[1, 2, "tHRee", 4]这样的数组,进行排序的话,就会报错. 我们还可以使用一种更灵活的排序方式,那就是使用sort的block版本 a = [1, 2, "three", "four", 5, 6] b = a.sort {|x,y| x.to_s <=> y.to_s} #x,y分别是每次传进来的两个元素. # b is now [1, 2, 5, 6, "four", "three"] x = [1, 4, 3, 5, 2] y = x.sort {|a,b| b <=> a} # [5, 4, 3, 2, 1] 当我们想要根据很多key来排序的话,我们使用sort方法,就显得非常麻烦 这个时候我们能够使用Enumerable 模块的sort_by方法 words=[1,2,"3"] puts words.sort #错误不能排序 puts lists =words.sort_by{|item| item.to_s} # 1 2 3
shift
char=[a,b,b,c].shift #删除数组中的第一个字符 puts char # a
想得到数组中某几个元素组成的数组,你可以使用values_at方法
x = [10, 20, 30, 40, 50, 60] y = x.values_at(0, 1, 4) # [10, 20, 50] z = x.values_at(0..2,5) # [10, 20, 30, 60]
[1,3,5,7,9].find{|v| v*v < 30 } #返回满足条件的第一个值 x.detect {|e| e % 2 == 0 } # 8 功能与find相同 如果我们想得到这个数组中所有的偶数 这是就该使用find_all方法,而select和find_all方法是同意的 # Continuing the above example... x.find {|e| e % 2 == 0} # 8 x.find_all {|e| e % 2 == 0} # [8, 12, 4, 30] x.select {|e| e % 2 == 0} # [8, 12, 4, 30] reject方法和select完全相反,看名字就知道了,它是选择不符合条件的 c = [5, 8, 12, 9, 4, 30] d = c.reject {|e| e % 2 == 0} # [5, 9] puts c.reject! {|e| e % 3 == 0} # c is now [5, 8, 4] ["H", "A", "L"].collect {|x| x.succ } #输下当前字符的下一字符 [1,3,5,7,9].each{|i| puts i } #遍历数组 [1,3,5,7].inject {|sum, element| sum+element} #数组求和 [1,3,5,7].inject {|product, element| product*element} #数组求积 a=Array.new #新建一个数组 a = [ 'ant', 'bee', 'cat', 'dog', 'elk' ] a[0] -> "ant" a[3] -> "dog" # this is the same: a = %w{ ant bee cat dog elk } a[0] -> "ant" a[3] -> "dog" y = [1, 2, nil, nil, 3, 4] c = y.size # 6 d = y.length # 6 e = y.nitems # 4 统计数组长度不包含nil
变量
全局变量 用$开头
实例变量用@开头
类变量 用@@ 开头person = "Tim" person.id -> 936870 person.class -> String person -> "Tim"
#{..} → 可以在引号中引用变量值或
def say_goodnight(name) result = "Good night, #{name.capitalize}" #.capitalize输出字符串首字母大写 return result end puts say_goodnight('uncle') 输出结果: Good night, Uncle
String
squeeze
我们可以使用squeeze 方法来一处重复的字符 s1 = "bookkeeper" puts s2 = s1.squeeze # "bokeper" s3 = "Hello..." puts s4 = s3.squeeze # "Helo." #If a parameter is specified, only those characters will be squeezed. puts s5 = s3.squeeze(".") # "Hello."
将一个字符串按照单词进行反转,那么你就会用到split方法和,数组的reverse方法
phrase = "Now here's a sentence" puts phrase.split(" ").reverse.join(" ") # "sentence a here's Now"
strip
strip将会删除掉字符串的开头和结尾的空格 sss="a d c " puts sss.strip => abc 如果你只想从字符串的开头或者结尾的空格,那么可以使用lstrip或者rstrip str = " abc " s2 = str.lstrip # "abc " s3 = str.rstrip # " abc"
chop
chop方法将会删除最后一个字符,返回新的string。如果字符是以\r\n结束,则两个字符都会被删除 str = "abcxyz" s1 = str.chop # "abcxy" str2="abc\r\n" s2=str2.chop #abc
chomp
str = "abcxyz" puts s1 = str.chomp #abcxyz str2 = "123\n" puts s2=str2.chomp #123 str1 = "abcxyz" str2 = "abcxyz" puts s1 = str1.chomp("yz") # "abcx" puts s2 = str2.chomp("x") # "abcxyz" #只匹配结尾的词
unpack
puts "E".unpack("c") #69 输出一个字符串的asc码值
«
puts "a"<<111 <<符号或者chr来把一个asc转换为字符串: puts 111.chr
scan
"hello world".scan(/./){|s| print s} #扫描匹配的字符串并打印
casecmp
n4 = "ABC".casecmp("abc") # 0 功能同<=>忽略大小写
puts
str="bobo" puts str.ljust(8,"++") #左对齐其余用++补齐 puts str.rjust(8,"++") #右对齐其余用++补齐
"Seconds/day: #{24*60*60}" -> Seconds/day: 86400 "#{'Ho! '*3}Merry Christmas!" -> Ho! Ho! Ho! Merry Christmas! "This is line #$." -> This is line 3 # #?显示程序块中语句所在的行号
each_byte
str="bobo" str.each_byte{|byte| puts byte.chr} 结果: b o b o
dup
person1 = "Tim" person2 = person1.dup #同.new功能相同也可以用person2=person1 person1[0] = "J" person1 -> "Jim" person2 -> "Tim"
freeze
person1 = "Tim" person2 = person1 person1.freeze # 字符串不可变 person2[0] = "J" 结果: prog.rb:4:in `[]=': can't modify frozen string (TypeError) from prog.rb:4
index & rindex
index方法返回指定的子字符串,正则表达式或者字符的起始位置(如果有多个匹配的只返回第一个匹配的起始位置) 没有发现的话返回nil,而rindex则是从string的右边(也就是结束处)开始查找,不过返回的值却是从左边数起的: str = "Albert Einstein" puts pos1 = str.index(?E) # 7 puts pos1 = str.index(69) # 7 puts pos2 = str.index("bert") # 2 puts pos3 = str.index(/in/) # 8 puts pos4 = str.index(?e) # nil puts pos5 = str.index("bart") # nil puts pos6 = str.index(/wein/) # nil
正侧表达式
sub或者gsub方法来进行替换,他们两个方法第一个参数都是接受正则表达式。 其中,sub方法替换掉第一个匹配的地方,而gsub方法替换掉全部匹配的地方: s1 = "spam, spam, and eggs" s2 = s1.sub(/spam/,"bacon") # "bacon, spam, and eggs" s3 = s2.sub(/(\w+), (\w+),/,'\2, \1,') # "spam, bacon, and eggs" s4 = "Don't forget the spam." s5 = s4.sub(/spam/) { |m| m.reverse } # "Don't forget the maps." 把匹配部分的单词反转 s5 = "alfalfa abracadabra" s6 = s5.gsub(/a[bl]/,"xx") # "xxfxxfa xxracadxxra" s5.gsub(/[lfdbr]/) { |m| m.upcase + "-" } # s5 is now "aL-F-aL-F-a aB-R-acaD-aB-R-a"
String类常用函数表
* | 将字符串拷贝N次 | “ha”*4 » “hahahaha” |
+ | 连接字符串 | “yes”+“no” » “yesno” |
« | 连接字符串 | “yes”+“no” » “yesno” |
concat | 连接字符串 | “yes”+“no” » “yesno” |
⇔ | 比较字符串,返回值: 大于=-1 | “Ab” ⇔ “ab” » -1 |
等于=0 | “ab” ⇔ “ab” » 0 | |
小于=1 | “ab” ⇔ “Ab” » 1 | |
== 或 === | 判断两个对象是否相等 | “1” == “1” » true , “1” == 1 » flase |
=~ | 匹配正则表达式 | “abc123abc” =~ /\d/ » 3 |
[ ] 或 slice | 返回字符串的某一范围内的值 | “abc”[0,2] » “ab”, “hello”[/llo/] » “llo”, “abc”.slice(0,2) » “ab” |
[]= | 替换字符串的某一范围内的值 | a=“hello word” → a[1,2]=“OO” → puts a »“hOOlo word” |
capitalize,capitalize! | 把字符串的首字母大写,其他字母小写 | “hi,Ruby”.capitalize » “Hi,ruby” |
chomp,chomp! | 删除字符串后的空白字符 | “string”r”n”.chomp »“string” |
chop | 删除最后一个字符 | “string”.chop » “strin” |
count | 返回该字符串中含的字符个数 | a = “hello world” → a.count “lo” » 5 #(l出现 3次,o出现 2次) |
基础
ruby打印输出命令 puts 带换行符输出 priint 不带换行符输出 ruby中区间表示 1..5表示1,2,3,4,5 1...5表示1,2,3,4