2016年9月11日 下午6:46 **
字符串
String 与 Symbol 这两个类提供了表示文字与处理文字的功能。这两个类之间很不同。
字符串表示
一个字符串一般用一组引号包装:
"这就是一个字符串"
单引号也行:
'我也是个字符串'
使用字符插值的时候得用双引号:
puts "二加二等于 #{2 + 2}" puts '二加二等于 #{2 + 2}'
输出的内容是:
二加二等于 4 二加二等于 #{2 + 2}
单引与双引在 escape 时的区别:
puts "Backslashes (\\) have to be escaped in double quotes." puts 'You can just type \ once in a single quoted string.' puts "But whichever type of quotation mark you use..." puts "...you have to escape its quotation symbol, such as \"." puts 'That applies to \' in single-quoted strings too.' puts 'Backslash-n just looks like \n between single quotes.' puts "But it means newline\nin a double-quoted string." puts 'Same with \t, which comes out as \t with single quotes...' puts "...but inserts a tab character:\tinside double quotes." puts "You can escape the backslash to get \\n and \\t with double quotes."
输出的是:
Backslashes (\) have to be escaped in double quotes. You can just type \ once in a single quoted string. But whichever type of quotation mark you use... ...you have to escape its quotation symbol, such as ". That applies to ' in single-quoted strings too. Backslash-n just looks like \n between single quotes. But it means newline in a double-quoted string. Same with \t, which comes out as \t with single quotes... ...but inserts a tab character: inside double quotes. You can escape the backslash to get \n and \t with double quotes.
下午6:59 **
下午7:24 **
其它的引用机制
还有一种引用机制,%char{text},下面的 %q 生成一个单引号字符:
puts %q{You needn't escape apostrophes when using %q.}
因为上面的字符串不是用单引号标记的,所以字符串里的撇号不用 escape 。
双引号用 %Q,%{} 也可以。分隔符也可以很随便:
%q-A string- %Q/Another string/ %[Yet another string]
Here 文档
here-doc,可以是多行字符串:
>> text = <<EOM This is the first line of text. This is the second line. Now we're done. EOM => "This is the first line of text.\nThis is the second line.\nNow we're done.\n"
<<EOM 开始,到 EOM 结束,EOM 是一个分隔符,它可以是任何字符串,EOM 是惯例 ,意思是 end of message。要左对齐,不想左对齐可以在 << 后面加一个 - :
>> text = <<-EOM The EOM doesn't have to be flush left! EOM => "The EOM doesn't have to be flush left!\n"
默认 here-docs 跟双引号字符串一样,可以解释它里面的字符插值,还有一些 escape 字符,比如 \n 或 \t 。如果你需要让 here-doc 像单引号字符串那样,可以这样:
>> text = <<-'EOM' Single-quoted! Note the literal \n. And the literal #{2+2}. EOM => "Single-quoted!\nNote the literal \\n.\nAnd the literal \#{2+2}.\n" >> puts text Single-quoted! Note the literal \n. And the literal #{2+2}. => nil
这样再试试:
>> a = <<EOM.to_i * 10 5 EOM => 50
再这样试一下:
>> array = [1,2,3,<<EOM,4] This is the here-doc. It becomes array[3] EOM => [1, 2, 3, "This is the here-doc.\nIt becomes array[3]\n", 4]
作为方法参数:
do_something_with_args(a, b, <<EOM) http://some_very_long_url_or_other_text_best_put_on_its_own_line EOM
字符串处理
获取与设置子字符串
[] 操作符可以得到一个字符串里的某个位置上的字符。提供一个索引号就行了,索引号是从零开始的,负数的索引指的是从字符串的最后往前数。
试一下:
>> string = 'Ruby is a cool language.' => "Ruby is a cool language." >> string[5] => "i" >> string[-12] => "o"
截取一段,再给 [] 提供一个 m 参数:
>> string[5,10] => "is a cool "
也可以用一个 range 对象作为参数:
>> string[7..14] => " a cool " >> string[-12..-3] => "ol languag" >> string[-12..20] => "ol langua" >> string[15..-1] => "language."
也可以直接给出你想得到的子字符串的内容,如果找到了就返回这个字符串,没找到就返回 nil:
>> string['cool lang'] => "cool lang" >> string['very cool lang'] => nil
正则表达式:
>> string[/c[ol ]+/] => "cool l"
slice 与 slice!:
>> string.slice!('cool') => "cool" >> string => "Ruby is a language."
[]= 方法可以设置找到的字符串:
>> string = 'Ruby is a cool language.' => "Ruby is a cool language." >> string['cool'] = 'great' => "great" >> string => "Ruby is a great language." >> string[-1] = '!' => "!" >> string => "Ruby is a great language!" >> string[-9..-1] = 'thing to learn' => "thing to learn" >> string => "Ruby is a great thing to learn"
合并字符串
>> 'a' + 'b' => "ab" >> 'a' + 'b' + 'c' => "abc"
+ 得到的永远都会是一个新的字符串,这样再试一下:
>> str = 'hi ' => "hi " >> str + 'there.' => "hi there." >> str => "hi "
再试试 << 方法,它会改变原始的字符串:
>> str = 'hi ' => "hi " >> str << 'there.' => "hi there." >> str => "hi there."
通过插值合并字符串
>> str = 'hi' => "hi" >> "#{str} there." => "hi there."
插值里可以是任何 Ruby 表达式:
>> "the sum is #{2+2}" => "the sum is 4"
不信再试试这个:
>> "My name is #{ >> class Person >> attr_accessor :name >> end >> d = Person.new >> d.name = 'David' >> d.name >> }." => "My name is David."
更好的方法:Ruby 在插值里会调用对象的 to_s 方法,你可以定义自己的 to_s 方法:
>> class Person >> attr_accessor :name >> def to_s >> name >> end >> end => :to_s >> david = Person.new => #<Person:0x007fbde8a195c0> >> david.name = 'David' => "David" >> "hello, #{david}!" => "hello, David!"
上面的例子里,我们把 david 作为插值,结果就是会调用它的 to_s 。
查询字符串
查询字符串有几种口味,有的可以给你响应布尔值,有的给你字符串在当前状态下的状态报告 。
布尔
你可以问字符串是不是包含某个子字符串,使用 include? ,试一下:
>> string = 'Ruby is a cool language.' => "Ruby is a cool language." >> string.include?('Ruby') => true >> string.include?('English') => false
开始:start_with?,结束:end_with?,再试试:
>> string.start_with?('Ruby') => true >> string.end_with?("!!!") => false
问一下字符串在不在:
>> string.empty? => false >> "".empty? => true
内容查询
得到字符串的尺寸:
>> string.size => 24
或:
>> string.length => 24
看一下指定的字符在字符串里出现了多少次:
>> string.count('a') => 3
一个范围的字符一共出现了多少次:
>> string.count('g-m') => 5
因为大小写敏感,所以再试一下:
>> string.count('A-Z') => 1
这样再试试:
>> string.count('aey. ') => 10
还有否定形式,使用 ^:
>> string.count('^aey. ') => 14 >> string.count('^g-m') => 19
换个花样:
>> string.count('ag-m') => 8 >> string.count('ag-m', '^1') => 8
查询字符在字符串里的索引,使用 index,反着查,使用 rindex:
>> string.index('cool') => 10 >> string.index('l') => 13 >> string.rindex('l') => 15
使用 ord 方法得到字符的序号编码:
>> 'a'.ord => 97
多个字符的话,只取第一个字符:
>> 'abc'.ord => 97
反过来:
>> 97.chr => "a"
下午9:46 ***
字符串比较与顺序
2016-09-12 08:09 ***
String 类里混合了 Comparable 模块,里面定义了 <=> 方法。所以你可以这样:
>> 'a' <=> 'b' => -1 >> 'b' > 'a' => true >> 'a' > 'A' => true >> '.' > ',' => true
<=> 方法在右边对象大的时候会返回 -1 ,左边对象大的时候返回 1 ,两个对象相等的时候返回 0。
'b' 大于 'a','a' 大于 'A',影响顺序的是字符值,'a' 是 97,'A' 是 65 。'.' 是 46,',' 是 44 。
比较是否相等
最常用的方法是 == ,试一下:
>> 'string' == 'string' => true >> 'string' == 'house' => false
两个 'string' 是不同的对象,但它们的内容是一样的。
String#eql? 方法也可以测试是否相等。它一般跟 == 是一样的。还有 String#equal? ,一般它比较的是两个对象是不是同一个对象。
>> 'a' == 'a' => true >> 'a'.eql?('a') => true >> 'a'.equal?('a') => false
字符串变形
字符串变形分成三大类:大小写,格式化,内容变形。
大小写
试试这些:
>> string = 'I Love You' => "I Love You" >> string.upcase => "I LOVE YOU" >> string.downcase => "i love you" >> string.swapcase => "i lOVE yOU"
首字母大写 capitalize/capitalize! :
>> string = 'i love you' => "i love you" >> string.capitalize => "I love you"
格式化
rjust,ljust 方法可以调整字符串的尺寸:
>> string = 'I Love You' => "I Love You" >> string.rjust(25) => " I Love You" >> string.ljust(25) => "I Love You "
给方法提供第二个参数:
>> string.rjust(25, '.') => "...............I Love You" >> string.ljust(25, '-') => "I Love You---------------"
试试 center 方法:
>> string.center(25, '*') => "*******I Love You********"
用 stip,lstrip,rstrip 方法去掉空白:
>> string = ' I Love You ' => " I Love You " >> string.strip => "I Love You" >> string.lstrip => "I Love You " >> string.rstrip => " I Love You"
内容变形
chop 与 chomp 方法可以删掉字符串结尾。chop 是无条件删除字符,chomp 如果在结尾找到目录子字符串,就会删除它。默认的 chomp 目录子字符是换行符。
试试:
>> "I Love You".chop => "I Love Yo" >> "I Love You\n".chomp => "I Love You" >> "I Love You".chomp("u") => "I Love Yo"
试一下 clear 的威力:
>> string = "I Love You" => "I Love You" >> string.clear => "" >> string => ""
替换:
>> string = "I..." => "I..." >> string.replace("I Love You") => "I Love You" >> string => "I Love You"
删除,参数的规则跟 count 方法的参数规则一样:
>> "I Love You".delete("oue") => "I Lv Y" >> "I Love You".delete("^o") => "oo" >> "I Love You".delete("a-e", "^c") => "I Lov You"
crypt,DES 数据加密,它唯一的参数是两位数的 salt 字符:
>> "I Love You".crypt("34") => "342C1ro5Q3yLQ"
succ:
>> "a".succ => "b" >> "abc".succ => "abd" >> "azz".succ => "baa"
字符串转换
参数是 2-36 这个范围的数字。
>> "100".to_i(17) => 289
不太明白 to_i 方法的参数的意思,是不是参数表示的是数字的位数,进制?base 17 ?base 8,base 16,不懂进制是什么意思。
8 位:oct,16 位:hex
>> "100".oct => 64 >> "100".hex => 256
to_f,转换成浮点不数,to_s,返回接收者,to_sym,intern ,转换成符号。
>> "1.2345".to_f => 1.2345 >> "hello".to_s => "hello" >> "abc".to_sym => :abc >> "1.23and some words".to_f => 1.23 >> "just some words".to_i => 0
字符串编码
源文件的编码
默认是 UTF-8 编码。可以这样确定一下,把下面代码放到一个文件里,然后再运行一下。
puts __ENCODING__
改变源文件的编码,可以使用一个 magic 注释在文件的顶部:
# encoding: encoding
比如设置成 US-ASCII:
# encoding: ASCII
个别字符串的编码
>> str = "test string" => "test string" >> str.encoding => #<Encoding:UTF-8>
设置字符串编码:
>> str.encode("US-ASCII") => "test string"
符号
符号是 Ruby 内置类 Symbol 的实例。它们的字面构造器是前面加冒号:
:a :book :"Here's how to make a symbol with spaces in it."
用 to_sym 方法创建符号:
>> "a".to_sym => :a >> "Coverting string to symbol with intern...".intern => :"Coverting string to symbol with intern..."
把符号改换成字符串:
>> :a.to_s => "a" >>
符号的主要特点
符号像字符串,很多时候又像整数。主要特点是:不变性与唯一性。
不变性
符号只要一存在,它就不能被改变。
唯一性
你看到一个符号 :abc,无论你在哪里看到它,它都是同一个对象。
做个实验:
>> "abc".object_id => 70179527234100 >> "abc".object_id => 70179527221160 >> :abc.object_id => 70179535013580 >> :abc.object_id => 70179535013580
符号与标识符
下面代码里包含了一个符号对象 :x ,还有一个本地变量标识符 s :
s = :x
Ruby 的内部会使用符号来跟踪它创建的所有的变量,方法,常量的名字。查看一下:
>> Symbol.all_symbols => [:inspect, :intern, :object_id, :const_missing, :method_missing, :method_added, :singleton_method_added, :method_removed, :singleton_method_removed,
给一个变量或常量分配一个值,创建了一个类,或写一个方法,你选择的标识符都会被 Ruby 放到它的符号表里。我们可以验证一下:
>> Symbol.all_symbols.size => 3481 >> abc = 1 => 1 >> Symbol.all_symbols.size => 3481 >> Symbol.all_symbols.grep(/abc/) => [:abc]
符号的使用
最常用的是作为方法的参数与 hash key 。
符号作为方法参数
attr_accessor :name attr_reader :age
send 方法可以不用点来发送信息,它可以接收一个符号:
"abc".send(:upcase)
send 也可以接收一个字符串参数,比如 upcase。不过你直接提供给它一个符号,就省了 Ruby 的事儿了,不然 Ruby 会在内部把字符串转换成符号。
符号作为 hash key
>> m_hash = { :title => "美丽人生", :year => 1997 } => {:title=>"美丽人生", :year=>1997} >> m_hash[:year] => 1997
差不多的 hash,使用的是字符串 key :
>> m_hash = { "title" => "美丽人生", "year" => 1997 } => {"title"=>"美丽人生", "year"=>1997} >> m_hash["title"] => "美丽人生"
符号作为 hash key 更快一些,看起来也比较好。
下面这个 hash :
has = { :title => "美丽人生", :year => 1997 }
也可以写成:
has = { title: "美丽人生", year: 1997 }
字符串与符号的比较
把符号想成是看起来像字符串一样的整数。
数字对象
在 Ruby 里数字也是对象,你可以给它发信息:
>> n = 99.6 => 99.6 >> m = n.round => 100 >> puts m 100 => nil >> x = 12 => 12 >> if x.zero? >> puts "x is zero" >> else ?> puts "x is not zero" >> end x is not zero => nil
数字类
- Numeric
- Float
- Integer
- Fixnum
- Bignum
算术
>> 1 + 1 => 2 >> 10 / 5 => 2 >> 16 / 5 => 3 >> 10 / 3.3 => 3.0303030303030303 >> 1.2 + 3.4 => 4.6 >> -12--7 => -5 >> 10 % 3 => 1
十六进制整数前面带 0x :
>> 0x12 => 18 >> 0x12 + 12 => 30
前面带 0 的是八进制整数:
>> 012 => 10 >> 012 + 12 => 22 >> 012 + 0x12 => 28
大部分算术操作其实都是方法,因为有语法糖所以看起来像是操作符,原本应该是这样的:
>> 1.+(1) => 2 >> 12./(3) => 4 >> -12.-(-7) => -5
时间与日期
导入 date:
>> require 'date' => true >> Date.parse("April 24 1705").england.strftime("%B %d %Y") => "April 13 1705"
处理时间与日期的有几个类:Time,Date,DateTime。它们的对象可以叫做 date/time 对象。使用它们先要导入:
require 'date' require 'time'
第一行提供了 Date 与 DateTime 类,第二行是 Time 类。在未来可能会把跟日期与时间的类组合到一块儿。
实例化 date/time 对象
创建日期对象
>> today = Date.today => #<Date: 2016-09-12 ((2457644j,0s,0n),+0s,2299161j)> >> today.to_s => "2016-09-12" >> puts today 2016-09-12 => nil
使用 Date.new 创建日期对象,要给它提供年,月,日:
>> puts Date.new(1959,2,1) 1959-02-01
如果不提供月与日的话,默认会是 1 。
用 parse 创建日期对象:
>> puts Date.parse("2012/7/22") 2012-07-22
>> puts Date.parse("03/6/9") 2003-06-09 >> puts Date.parse("33/6/9") 2033-06-09 >> puts Date.parse("77/6/9") 1977-06-09 >> puts Date.parse("November 2 2013") 2013-11-02 >> puts Date.parse("Nov 2 2013") 2013-11-02 >> puts Date.parse("2 Nov 2013") 2013-11-02 >> puts Date.parse("2013/11/2") 2013-11-02
创建时间对象
创建时间对象:new(又叫 now),at,local(又叫 mktime),parse。
>> Time.new => 2016-09-12 10:47:31 +0800 >> Time.at(100000000) => 1973-03-03 17:46:40 +0800 >> Time.mktime(2007,10,3,14,3,6) => 2007-10-03 14:03:06 +0800 >> require 'time' => false >> Time.parse("March 22, 1985, 10:35 PM") => 1985-03-22 22:35:00 +0800
epoch (midnight on January 1, 1970, GMT)
创建 date/time 对象
DateTime 是 Date 的子类。
>> puts DateTime.new(2009, 1, 2, 3, 4, 5) 2009-01-02T03:04:05+00:00 => nil >> puts DateTime.now 2016-09-12T10:54:22+08:00 => nil >> puts DateTime.parse("October 23, 1973, 10:34 AM") 1973-10-23T10:34:00+00:00 => nil
jd(Julian date),commercial,strptime
date/time 查询方法
>> dt = DateTime.now => #<DateTime: 2016-09-12T10:57:55+08:00 ((2457644j,10675s,478039000n),+28800s,2299161j)> >> dt.year => 2016 >> dt.hour => 10 >> dt.minute => 57 >> dt.second => 55 >> t = Time.now => 2016-09-12 10:58:12 +0800 >> t.month => 9 >> t.sec => 12 >> d = Date.today => #<Date: 2016-09-12 ((2457644j,0s,0n),+0s,2299161j)> >> d.day => 12
今天礼拜几?
>> d.monday? => true >> d.friday? => false
date/time 格式化方法
所有的 date/time 对象都有 strftime 方法。
>> t = Time.now => 2016-09-12 11:08:22 +0800 >> t.strftime("%y-%m-%d") => "16-09-12" >> t.strftime("%Y-%m-%d") => "2016-09-12"
- %Y:四位数的年
- %y:两位数的年
- %b,%B:短月,长月
- %m:数字月
- %d:日,左带零
- %e:日
- %a,%A:短日名,长日名
- %H,%I:小时,24,12。
- %M:分
- %S:秒
- %c:%a %b %d %H:%M:%S %Y
- %x:%m/%d/%y
RFC 2822 (email),RFC 2616(http):
>> Date.today.rfc2822 => "Mon, 12 Sep 2016 00:00:00 +0000" >> DateTime.now.httpdate => "Mon, 12 Sep 2016 03:15:24 GMT"
date/time 转换方法
Time 有 to_date ,to_datetime 方法,Date 有 to_time,to_datetime 方法,DateTime 有 to_time,to_date 方法。
date/time 算术
>> t = Time.now => 2016-09-12 11:18:29 +0800 >> t - 20 => 2016-09-12 11:18:09 +0800 >> t + 20 => 2016-09-12 11:18:49 +0800
月的转换:
>> dt = DateTime.now => #<DateTime: 2016-09-12T11:19:25+08:00 ((2457644j,11965s,940690000n),+28800s,2299161j)> >> puts dt + 100 2016-12-21T11:19:25+08:00 => nil >> puts dt >> 3 2016-12-12T11:19:25+08:00 => nil >> puts dt << 10 2015-11-12T11:19:25+08:00 => nil
天:
>> d = Date.today => #<Date: 2016-09-12 ((2457644j,0s,0n),+0s,2299161j)> >> puts d.next 2016-09-13 => nil >> puts d.next_year 2017-09-12 => nil >> puts d.next_month 2016-10-12 => nil >> puts d.prev_day(10) 2016-09-02 => nil
upto,downto:
>> d = Date.today => #<Date: 2016-09-12 ((2457644j,0s,0n),+0s,2299161j)> >> next_week = d + 7 => #<Date: 2016-09-19 ((2457651j,0s,0n),+0s,2299161j)> >> d.upto(next_week) {|date| puts "#{date} is a #{date.strftime("%A")}"} 2016-09-12 is a Monday 2016-09-13 is a Tuesday 2016-09-14 is a Wednesday 2016-09-15 is a Thursday 2016-09-16 is a Friday 2016-09-17 is a Saturday 2016-09-18 is a Sunday 2016-09-19 is a Monday => #<Date: 2016-09-12 ((2457644j,0s,0n),+0s,2299161j)>
查看帮助:ri Date
11:24 ****
Ruby