🦄 2024 独立开发者训练营,一起创业!查看介绍 / 立即报名(剩余10个优惠名额) →

Day 8:Ruby 字符串,符号,数字,日期

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
微信好友

用微信扫描二维码,
加我好友。

微信公众号

用微信扫描二维码,
订阅宁皓网公众号。

240746680

用 QQ 扫描二维码,
加入宁皓网 QQ 群。

统计

15260
分钟
0
你学会了
0%
完成

社会化网络

关于

微信订阅号

扫描微信二维码关注宁皓网,每天进步一点