第5章 条件判断

ruby的三种主要条件判断语句

  • if
  • unless
  • case

Ruby真假值

|真|假| |–|–| |真|false、nil以外的所有对象| |假|false、nil|

if语句

if 条件 then 
end

then 可以省略

unless语句

条件为假时执行

unless 条件 then
end

then 可以省略

case语句

case 比较对象
when 1 then
  处理1
when 2 then
  处理2
when 3 then
  处理3
else
  处理4
end

then 可以省略

=== 与 case

在case语句中,when判断值是否相等时,实际是使用===运算符来判断。左边是数值或字符串时,===与==意义一样,除此之外,===还可以与=~一样用来判断正则表达式是否匹配,或者判断右边的对象是否属于左边的类,等等。对比单纯的判断两边的值是否相等,===能表达更加广义的”相等”。

eql? 判断值相等比 == 严谨

例如:0 与 0.0 和 1.0 与 1 eql? 返回 false ==返回 true

第6章 循环

实现循环的方法

  • times 方法
  • while 语句
  • each 方法
  • for 语句
  • until 语句
  • loop 方法

times方法

# 满地油菜花输出7遍
7.times do
  puts "满地油菜花"
end

得到当前的循环次数

10.times do |i|
  puts i
end

for语句

for语句与times方法不一样,循环的开始值和结束值可以任意指定。

sum = 0
for i in 1..5 do
  sum = sum + i
end
puts sum

do可以省略

计算变量from到变量to累加的总数

from = 10
to = 20
sum = 0
for i in from..to
  sum = sum + i
end
puts sum

普通for语句

names = ["awk", "Perl", "Python", "Ruby"]
for name in names
  puts name
end

while语句

i = 1
while i < 3
  puts i
  i += 1
end

until语句

until语句的结构与white完全一样,只是条件判断刚好相反,不满足条件时才执行循环处理

each方法

each方法将对象集合里的对象逐条取出

names = ["awk", "Perl", "Python", "Ruby"]
names.each do |name|
  puts name
end
sum = 0
(1..5).each do |i|
  sum = sum + i
end
puts sum

loop方法

loop方法没有终止条件,只是不断的执行循环

循环控制

  • break 终止程序,跳出循环
  • next 跳到下一次循环
  • redo 在相同的条件下重复刚才的处理

break

break会终止全体循环程序

next

next会忽略next后面的部分,跳到下一个循环开始的部分

redo

redo和next非常像,与next不同之处是,redo会再执行一次相同的循环 break和next比较常用,redo在ruby默认提供的程序库里也很难找到踪影

do ~ end 与 { ~ }

一般的约定

  • 程序是跨行写的时候使用 do ~ end
  • 程序写在1行的时候用 { ~}

第7章 方法

方法调用

对象.方法名(参数1, 参数2,  ,参数n)

对象被称为接收者(receiver)。在面向对象的世界中,调用方法被称为『向对象发送消息(message)』,调用的结果就是『对象接收(receive)了消息』,也就是说,方法的调用就是把几个参数连同消息一起发送给对象的过程。

带块的方法调用

each 和 loop 等方法都属于带块的方法

使用do ~ end是,可以省略参数列表括起来的()。使用{~}时,只有在没有参数的时候才可以省略()。

运算符形式的方法调用

Ruby中有些方法看起来很像运算符。四则运算等的二元运算符、-(负号)等的一元运算符、指定数组、散列的元素下标的[]等,实际都是方法。

  • obj + arg1
  • obj =~ arg1
  • -obj
  • !obj
  • obj[arg1]
  • obj[arg1] = arg2

实际上可以将obj理解为接收者,将arg1、arg2理解为参数。

方法的分类

Ruby的方法分为3类:

  • 实例方法
  • 类方法
  • 函数式方法

实例方法

如果有一个对象的实例,那么以这个对象为接收者的方法就是实例方法。

p "10, 20, 30, 40".split(",")
p [1, 2, 3, 4].index(2)
p 1000.to_s

类方法

接收者不是对象而是类本身时的方法,是类方法。

Array.new
File.open("some_file")
Time.now

调用类方法时,可以使用::代替.。Ruby语法中 :: 和 . 代表的意思是一样的。

函数式方法

没有接收者的方法是函数式方法。

print "hello!"
sleep(10)

函数式方法的执行结果,不会根据接收者的状态而发生变化。程序运行print方法以及sleep方法的时候,不需要知道接收者是谁。反过来说,不需要接收者的方法就是函数式方法。

Ruby帮助文档里实例方法的标记法

Ruby帮助文档里标记类的实例方法用Array#each、Array#inject写法。

方法的定义

定义方法的一般语法:

def 方法名 (参数1 参数2)
  希望执行的代码
end

方法名可以由英文字母、数字、下划线组成,但不能以数字开头。

方法有多个参数时,从参数列表右边开始依次指定默认值。

def func(a, b=1, c=3)
end

方法的返回值

可以用return指定方法的返回值

可以省略return语句,方法的最后一个表达式的结果作为方法的返回值

return语句可以马上终止程序

定义带块的方法

def myloop
  while true
    yield # 执行块
  end
end

num = 1   # 初始化num
myloop do
  puts "num is #{num}"
  break if num > 100     # num超过100时跳出循环
  num * 2
end

yield是定义块的关键字

参数个数不确定的方法

通过 『*变量名』 的形式来定义参数个数不确定的方法

def foo(*args)
  args
end

p foo(1, 2, 3)   #=> [1, 2, 3]

def meth(arg, *args)
  [arg, args]
end

p meth(1)         #=> [1, []]
p meth(1, 2, 3)   #=>[1, [2, 3]]

关键字参数

Ruby 2.0加入的新特性

def 方法名(参数1:, 参数2:)
  代码逻辑
end

可以使用 『**变量名』这种形式来接收未定义的参数

关键字参数可以与普通参数搭配使用

可以使用散列传递参数

关于方法调用的一些补充

  • 把数组分解为参数
  • 把散列作为参数传递

如何书写简明易懂的程序

  • 换行和;
    • 多使用换行作为语句的间隔
    • 除非必要,不使用;作为语句的间隔
  • 缩进(indent)
    • 两个空白表示一个缩进
    • 需要使用缩进的情况:
      • 条件分支
      • 循环
      • 方法、类等定义
    • 不要突然使用缩进
    • 确保缩进整齐
  • 空白
    • 好的写法
      • a+b
      • a + b
    • 不好的写法
      • a +b
      • a+ b
  • 良好的编码风格需要大量阅读其他人写的程序

第8章 类和模块

8.1 类是什么

8.1.1

想知道某个对象属于哪个类,可以使用class方法

ary = []
str = 'Hello World.'
p ary.class   #=> Array
p str.class   #=> String

判断某个对象是否属于某个类时,使用instance_of?方法

ary = []
str = 'Hello World'
p ary.instance_of?(Array)   #=> true
p str.instance_of?(String)  #=> true
p ary.instance_of?(String)  #=> false
p str.instance_of?(Array)   #=> false

8.1.2 继承

  • 通过扩展已定义的类来创建新类称为继承
  • 继承后创建创建的新类称为子类(subclass)
  • 被继承的类称为父类(superclass),也称超类
  • 通过继承可以实现以下事情:
    • 在不影响原有功能的前提下追加新功能
    • 重新定义原有功能,使名称相同的方法产生不同的效果
    • 在已有功能的基础上追加处理,扩展已有功能
  • BasicObject类是Ruby中所有类的父类,它定义了作为Ruby对象的最基本功能

8.2 类的创建

使用class关键字定义类

class 类名
  类的定义
end

8.2.2 initialize 方法

使用new方法生成新对象时,initialize方法会被调用,new方法的参数会原封不动的传给initialize方法

 # initialize方法
def initialize(myname='Ruby')  
  @name=myname                  # 初始化实例变量
end

8.2.3 实例变量与实例方法

实例方法在实例内可用

8.2.4 存取器

class HelloWorld

  # 获取name
  def name
    @name
  end

  # 修改name
  def name=(value)
    @name = value
  end

Ruby提供了简便的定义方法

  • attr_reader 只读
  • attr_writer 只写
  • attr_accessor 读写

8.2.5 特殊变量 self

self是引用对象本身的保留字,对它赋值,不会对本身的值有任何影响

8.2.6 类方法

class << HelloWorld
  def hello(name)
    puts "#{name} said hello."
  end
end

HelloWorld.hello('John')  #=> John said hello.

class HelloWorld
  class << self
    def hello(name)
      puts "#{name} said hello."
    end
  end
end

HelloWorld.hello('John')  #=> John said hello.

def HelloWorld.hello(name)
  puts "#{name} said hello."
end

HelloWorld.hello('John')  #=> John said hello.

class HelloWorld
  def self.hello(name)
    puts "#{name} said hello."
  end
end

HelloWorld.hello('John')  #=> John said hello.

8.2.7 常量

class HelloWorld
  Version = "1.0"
end

使用类常量

p HelloWorld::Version    #=> "1.0"

8.2.8 类变量

@@开头的变量称作类变量,类变量是该类所有实例的共享变量

class HelloCount
  @@count = 0

  def HelloWorld.count
    @@count
  end

  def initialize(myname="Ruby")
    @name = myname
  end

  def hello
    @@count += 1
    puts "Hello, World. I am #{@name}.\n"
  end
end

bob = HelloCount.new("Bob")
alice = HelloCount.new("Alice")
ruby = HelloCount.new

p HelloCount.count  #=> 0
bob.hello
alice.hello
ruby.hello
p HelloCount.count  #=> 3

8.2.9 限制方法的调用

限制方法的调用

  • public 实例方法,对外部公开
  • private 无法从实例外部访问
  • protected 在同一个类中使用时,可做实例方法调用

8.3 扩展类

8.3.1 在原有类基础上添加方法

给String类添加统计单词数实例方法

class String
  def count_word
    ary = self.split(/\s+/) # 使用空格分割
    return ary.size         # 返回分割后数组元素总数
  end
end

str = "Just Another Ruby Newbie"
p str.count_word            #=> 4

8.3.2 继承

定义继承时,在使用class关键字指定类名的同时指定父类名

class 类名 < 父类名
  类定义
end
class RingArray < Array
  def [](i)
    idx = i % size
    super(idx)
  end
end

wday = RingArray['日', '火', '水', '木', '金', '土']
p wday[6]   #=> '土'
p wday[11]  #=> '木'
p wday[15]  #=> '月'
p wday[-1]  #=> '土'

8.4 alias 与 undef

8.4.1 alias

alias 别名 原名     # 直接使用方法名
alias :别名 :原名   # 使用符号名

同一种功能设置多个名称时,我们使用alias

class C1
  def hello
    "Hello"
  end
end

class C2 < C1
  alias old_hello hello

  def hello
    "#{old_hello}, again"
  end
end

obj = C2.new
p obj.old_hello
p obj.hello

8.4.2 undef

undef用于删除已有方法的定义。

undef 方法名    # 只用使用方法名
undef :方法名   # 使用符号名

8.5 模块

模块是Ruby的特色功能之一。如果说类变现的是事物的实体(数据)和行为(处理),那模块表现的就只是事物的行为部分。模块和类有两点不同:

  • 模块不能拥有实例
  • 模块不能被继承

8.6 模块的使用方法

8.6.1 提供命名空间

调用方法

模块名.方法名

8.6.2 利用Mix-in扩展功能

Mix-in就是将模块混合到类中

Mix-in可以灵活的解决下面问题:

  • 两个类拥有相似功能,但不希望作为相同种类(Class)考虑
  • Ruby不支持父类多重继承,因此无法对已经继承的类添加共通的功能的时候
module MyModule
  # 共通的方法
end

class MyClass1
  include MyModule
  # MyClass1独有方法
end

class MyClass2
  include MyModule
  # MyClass2独有方法
end

8.7 创建模块

module 模块名
  模块定义
end
module HelloModule
  Version = "1.0"

  def hello(name)
    puts "Hello, #{name}"
  end

  module_function :hello
end

8.7.1 常量

p HelloModule::Version    #=> "1.0"

8.7.2 方法的定义

8.8 Mix-in

  • 想知道类是否包含某个模块,可以使用include?方法
  • 用ancestors方法和superclass方法调查类的继承关系
module M
  def meth
    "meth"
  end
end

class C
  include M
end

c = C.new
p c.meth

C.include?(M)   #=> true
p C.ancestors   #=> [C, M, Object, BasicObject]
p C.superclass  #=> Object

8.8.1 查找方法的规则

  • 同继承关系一样,原类中已经定义了同名的方法时,优先使用该方法
  • 在同一类中包含多个模块时,优先使用最后一个包含模块
  • 嵌套include时,查找顺序也是线性的
  • 相同的模块被包含两次以上时,第2次以后的会被省略

8.8.2 extend方法

module Edition
  def edition(n)
    "#{self}#{n}版"
  end
end

str = "Ruby基础教程"

str.extend(Edition)

p str.edition(4)    #=> "Ruby基础教程第4版"

include可以帮助我们突破继承的限制,通过模块扩展类的功能;而extend则可以帮助我们跨过类,直接通过模块扩展对象的功能。

8.8.3 类与Mix-in

我们可以把类方法理解为:

  • Class类的实例方法
  • 类对象的单例方法

8.9 面向对象程序设计

8.9.1 对象是什么

面向对象语言的「对象」是指数据及操作数据方法的组合

8.9.2 面向对象的特征

  • 封装
  • 多态

第9章 运算符

9.1 赋值运算符

9.2 逻辑运算符的应用

  • 表达式的执行顺序是从左到右
  • 如果逻辑表达式真假已经可以确定,则不会判断剩余表达式
  • 最后一个表达式的值为整理逻辑表达式的值

9.3 条件运算符

条件  表达式1 : 表达式2

9.4 范围运算符

范围对象range

Range.new(1, 10)
1..10

x..y是从x到y x…y是从x到y的前一个

9.5 运算符优先级

从高到低排序

  • ::
  • []
    • ! ~
  • **
  • -
    • / %
    • -
  • « »
  • &
  • ^
  • = < <=

  • <=> == === != =~ !~
  • &&
  •  
  • ?:
  • .. …
  • = (包含+= -= /=)
  • not
  • and or

如果不想按照优先顺序计算,可以使用()起来

9.6 定义运算符

不允许修改的运算符

  • ::
  • &&
  •  
  • ..
  • ?:
  • not
  • =
  • and
  • or

9.6.1 二元运算符

第10章 错误处理与异常

10.3 异常处理的写法

begin
  可能发生错误的处理
rescue
  发生错误时的处理
end

rescue后指定变量名,可获得异常对象

begin
  可能发生错误的处理
rescue => 引用异常对象的变量
  发生错误时的处理
end

异常发生时被自动赋值的变量:

  • $! —— 最后发生的异常(异常对象)
  • $@ —— 最后发生异常的位置信息

异常对象的方法:

  • class 异常的种类
  • message 异常信息
  • backtrace 异常发生的位置

第11章 块

11.1 块是什么

块就是在调用方法时,能与参数一起传递的多个处理的集合

[1, 2, 3, 4, 5].each do |i|
  puts i ** 2
end

do和end之间的就是块

第13章 数组类

13.5 作为列的数组

  • 队列是一种按照元素被追加顺序来获取元素的数据结构。这样的做法称为FIFO(First-in First-out),也就是先进先出。
  • 而栈则是一种按照与元素被追加时顺序相反的顺序来获取元素的数据结构。这样的做法叫做LIFO(Last-in First-out),是一种『先进后出』的数据结构。 ## 13.6 主要的数组方法

13.6.1 为数组添加元素

  • a.unshift(item) 将item元素添加到数组开头
  • a«item 和 a.push(item) « 与 push 等价,是在数组a末尾添加新元素item
  • a.conact(b) 和 a+b 连接数组a和b。concat是具有破坏性的方法,而+则会返回新数组
  • a[n]=item; a[n..m]=item; a[n,len]=item 将a数组指定部分的元素替换为item

13.6.2 从数组中删除元素

a.compact a.compact!

从数组a中删除nil元素。 compact方法返回新数组,compact!则直接替换原来的数组

a.delete(x) 从数组a删除x元素

a = [1, 2, 3, 2, 1]
a.delete(2)
p a   #=> [1, 3, 1]

a.delete_at(n) 从数组a中删除a[n]元素

a = [1, 2, 3, 4, 5]
a.delete_atl(2)
p a   #=> [1, 2, 4, 5]
a.delete_if{ item … }
a.reject{ item … }
a.reject!{ item … }

判断数组a中个元素item,如果块的执行结果为真,则从数组a中删除item。delete_if和reject!方法都是具有破坏性的方法。

a.slice!(n) a.slice!(n..m) a.slice!(n, len) 删除数组a中指定的部分,并返回删除部分的值。slice!是具有破坏性的方法。

a = [1, 2, 3, 4, 5]
p a.slice!(1, 2)    #=> [2, 3]
p a                 #=> [1, 4, 5]

a.uniq a.uniq!

删除数组a中重复的元素,uniq!是具有破坏性的方法

a = [1, 2, 3, 4, 3, 2, 1]
a.uniq!
p a   #=> [1, 2, 3, 4]

a.shift 删除数组a开头的元素

a.pop 删除数组a末尾的元素

13.6.3 替换数组元素

13.7 数组与迭代器

迭代器是实现循环处理的方法,而数组则是多个对象的集合

13.8 处理数组中的元素

13.8.1 使用循环与索引

list = ["a", "b", "c", "d"]
for i in 0..3
  print "第", i+1,"个元素是",list[i],".\n"
end

13.8.2 使用each方法逐个获取元素

list = [1, 3, 5, 7, 9]
sum = 0
list.each do |elem|
  sum += elem
end
print "合计:",sum,"\n"

指定元素索引值 each_with_index

list = ["a", "b", "c", "d"]
list.each_with_index do |elem, i|
  print "第", i+1, "个元素是", elem,".\n"
end

13.8.3 使用具有破坏性的方法实现循环

while item = a.pop
  ## 对item进行处理
end

13.8.4 使用其他迭代器

  • collect
  • map

13.8.5 创建专用迭代器

参考 11.3

13.9 数组元素

13.9.1 使用简单矩阵

a = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

取出元素6

a[1][2]

第14章 字符串类

14.1 字符串的创建

str1 = "这是字符串"
str2 = '那也是字符串'

使用\转义特殊字符

  • \t 水平制表符
  • \n 换行符
  • \r 回车
  • \f 换页
  • \b 退格
  • \a 响铃
  • \e 溢出
  • \s 空格
  • \v 垂直制表符
  • \nnn 8进制表示方式
  • \Xnn 16进制表示方式
  • \Cx、\C-x Control + x
  • \M-x Meta(Alt) + x
  • \M-\C-x Meta(Alt) + Control + x
  • \x 表示x字符本身(x为除以上字符的字符)
  • \Unnnn Unicode字符的16进制表示方式

14.1.1 使用%Q与%q

  • %Q相当于用” “创建字符串
  • %q相当于用’ ‘创建字符串
desc = %Q{Ruby的字符串中也可以使用''和""}
str = %q|Ruby said, 'Hello world!'|

14.1.2 使用Here Document

Here Document源于Unix的shell的一种写法,«来创建字符串

14.1.3 使用sprintf方法

参考printrf方法与sprintf方法

14.1.4 使用``

irb --simple-prompt
`ls -l /etc/hosts`

14.2 获取字符串长度

length和size方法获得字符串长度,两者的返回结果相同。

p '面向对象编程语言'.length	#=> 8

需要获得字节数可以使用bytesize方法

p '面向对象编程语言'.bytesize	#=> 24

想知道字符串长度是否为0,使用empty?方法

14.3 字符串索引

str = "全新的String类对象"
p str[0]	#=> "全"
p str[3]	#=> "S"
p str[2, 8]	#=> "的String类"

14.4 字符串的连接

连接字符串的两种方法:

  • 将两个字符串合并为新字符串
  • 扩展原有字符串

14.5 字符串的比较

使用==或者!=判断字符串是否相等

14.9.3 与连接、反转(reverse)相关的方法

s.reverse s.reverse! 反转字符串

s = "晚上好"
p s.reverse   #=> "好上晚"

14.10 其他方法

s.strip s.strip!

这是删除字符串s开头和结尾空白字符的方法

  • s.upcase 大写
  • s.upcase!
  • s.downcase 小写
  • s.downcase!
  • s.swapcase 大写字母转换小写,小写字母转换大写
  • s.swapcase!
  • s.capitalize 首字母大写
  • s.capitalize!

第15章 散列类

15.2 散列的创建

15.2.1 使用{}

{键 => 值}

h1 = {"a"=>"b", "c"=>"d"}
p h1["a"]	#=> "b"

{健: 值}

h2 = {a: "b", c: "d"}
p h2	#=> {:a=>"b", :c=>"d"}

15.2.2 使用Hash.new

h1 = Hash.new
h2 = Hash.new("")
p h1["not_key"]		#=> nil
p h2["not_key"]		#=> ""

15.3 值的获取与设定

使用[]获取键相对应的元素值

h = Hash.new
h["R"] = "Ruby"
p h["R"]	#=> "Ruby"

另外可以使用store方法设定,fetch方法获取值

h = Hash.new
h.stroe("R", "Ruby")
p h.fetch("R")		#=> "Ruby"

使用fetch方法时,有一点与[]不一样,如果散列中不存在指定键,程序会发生异常; 如果对fetch方法指定第2个参数,那么该参数值就会作为键不存在时散列的默认值; fetch方法还可以使用块,此时块的结果为散列的默认值

h = Hash.new
p h.fetch("N"){String.new}		#=> ""

15.3.1 一次性获取所有键、值

  • 获取键
    • 数组形式: keys方法
    • 迭代器形式: each_key{ ……}
  • 获取值
    • 数组形式: values方法
    • 迭代器形式: each_value{ ……}
  • 获取键值对[键,值]
    • 数组形式: to_a
    • 迭代器形式: each{ 键, 值 ……} each{ 数组 ……}

15.3.2 散列的默认值

  1. 创建散列时指定默认值
h = Hash.new(1)
h["a"] = 10
p h["a"]	#=> 10
p h["x"]	#=> 1
p h["y"]	#=> 1
  1. 通过块指定默认值
h = Hash.new do |hash, key|
	hash|key| = key.upcase
end
p h["a"]	#=> "b"
p h["x"]	#=> "x"
p h["y"]	#=> "y"

15.4 查看指定对象是否为散列的键或值

h.key?(key) h.has_key?(key) h.include?(key) h.member?(key)

上面4个方法都是查看指定对象是否为散列的键的方法,用法和效果都一样

h.value?(value) h.has_value?(value) 上面两2个方法用来检查值是否在指定的对象中

查看散列的大小

  • h.size
  • h.length

可以用length方法或者size方法查看散列的大小

  • h.empty?

可以empty?方法来查看散列的大小是否为0

15.6 删除键值

  • h.delete(key)

通过键删除用delete方法,delete方法可以使用块,如果不存在键,返回块执行结果

h = {"R"=>"Ruby"}
p h.delete("P"){|key| "no #{key}."}   #=> "no P."
  • h.delete_if{ key, val ……}
  • h.reject!{ key, val ……}
h = {"R"=>"Ruby", "p"=>"Perl"}
p h.delete_if{|key, value| key == "P"}  #=> {"R"=>"Ruby"}

reject!方法和delete_if方法用法相同,但当不符合条件时,两者返回值各异。delete_if返回原来的散列,reject!返回nil

15.7 初始化散列

  • h.clear

使用clear方法清空使用过的散列

h = {"a"=>"b", "c"=>"d"}
h.clear
p h.size    #=> 0

第16章 正则表达式类

16.1 关于正则表达式

16.1.1 正则表达式的写法与用法

一般情况我们把正则表达式对象(Regexp类对象)称为『正则表达式对象』,或直接称为『正则表达式』

16.1.2 正则表达式创建方法

在程序中,通过用//将正则表达式模式的字符串括起来,就可以非常简单的创建出正则表达式

另外可以使用类方法Regexp.new(str)来创建对象

re = Regexp.new("Ruby")

使用%r创建正则表达式

%r(模式)
%r<模式>
%r|模式|
%r!模式!

16.2 正则表达式的模式与匹配

正则表达式 =~ 字符串

无法匹配时返回nil,匹配成功返回该字符串起始字符的位置

if 正则表达式 =~ 字符串
  匹配时处理
else
  不匹配时处理
end

可以使用!~颠倒「真」与「假」

16.2.1 匹配普通字符

16.2.2 匹配行首与行尾

  • ^ 代表行首
  • $ 代表行尾

16.2.3 指定匹配字符的范围

有时候我们想匹配『ABC』中的1个字符,可以使用[]

[AB]      # 匹配A或B
[ABC]     # 匹配A或B或C
[CBA]     # 同上,与[]中的顺序无关
[012ABC]  # 0、1、A、B、C中的一个字符

16.2.4

使用.匹配任意1个字符

16.2.5 使用反斜杠的模式

  • \s 表示空白字符,匹配空格(0x20)、制表符(Tab)、换行符、换页符
  • \d 配备0到9的数字
  • \w 匹配英文字母与数字
  • \A 匹配字符串的开头
  • \z 匹配字符串的末尾
  • \ 元字符串转义

16.2.6 重复

    • 重复0次以上
    • 重复1次以上
  • ? 重复0次或1次

16.2.7 最短匹配

  • *? 0次以上的重复中最短的部分
  • +? 1次以上的重复中最短的部分

16.2.8 ()与重复

16.3 使用quote方法的正则表达式

16.4 正则表达式的选项

正则表达式还有选项,使用选项可以改变正则表达式的一些默认效果。 设定正则表达式的选项时,只需在/…/后面指定即可,如:/…/im

  • i 忽略英文字母大小写
  • x 忽略正则表达式中的空白字符以及#后面的字符,指定这个选项,我们就可以使用#在正则表达式中写注释
  • m 指定这个选项可以使用.匹配换行符

16.5 捕获

所谓捕获,就是从正则表达式的就匹配部分中提取其中的某部分。通过”$数字”这种形式的变量,就可以获取匹配了正则表达式中用()扩住的部分字符串。

除了”$数字”这种形式,保存匹配结果的变量还有:

  • $` 匹配部分前的字符串
  • $& 匹配的字符串
  • $’ 匹配部分后的字符串
/C./ =~ 'ABCDEF'
p $\``   #=> "AB"
p $&    #=> "CD"
p $'    #=> "EF"     

16.6 使用正则表达式的方法

16.6.1 sub方法与gsub方法

sub方法与gsub方法的作用是用指定的字符串置换字符串中的某部分字符

sub方法只置换首次匹配的部分,而gsub方法则会置换所有匹配的部分

str = "abc   def   g   hi"
p str.sub(/\s+/, ' ')    #=> "abc def  g  hi"
p str.gsub(/\s+/, ' ')   #=> "abc def g hi"

sub方法和gsub方法还可以使用块,这时程序将字符串中匹配的部分传递给块,并在块中使用该字符串进行处理。

16.6.2 sacn方法

sacn方法像gsub方法那样捕获匹配部分的字符串,但不能做置换操作