从六开始——文件分析与瘦身

学习Ruby简单语法

2019-10-18  本文已影响0人  肠粉白粥_Hoben

上文讲到,要生成LinkMap,就要修改Build Setting里面的一些Flag,如果需要用脚本来控制,则需要修改到.xcodeproj文件。

今早研究了一早的Python语法,发现都没有很好的办法去修改这个Flag,恰好看到别的文章有思路说,用Ruby来修改,试了一下,果不其然成功了,一不做二不休,干脆把Ruby的简单语法也了解一下吧!

教程来自ruby基础教程(中文第四版)

一. Hello World

print("Hello World!\n")

二. 数组+循环

1. each方法

names = ["a", "b", "c"]

puts names[0]

names.each do |n|
    puts n
end

/***
输出
a
a
b
c
***/

数组就很常见了,下面着重讲一下循环:

在Ruby语法中,array.each do |element| end,代表着枚举一个array的元素element,循环起于do而终于end。

2. times方法

5.times do |n|
    puts n
end

/***
输出
0
1
2
3
4
***/

3. for方法

sum = 0

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

/***
输出
1
3
6
10
15
***/

4. while方法

sum = 0

i = 1

while i <= 5
    sum = sum + i
    i += 1
    puts sum
end

/***
输出
1
3
6
10
15
***/

5. break, next

array = ["a", "b", "c", "d", "e"]

array.each do |element|
    break if element == "c"
    puts element
end

/***
输出
a
b
***/
array = ["a", "b", "c", "d", "e"]

array.each do |element|
    next if element == "c"
    puts element
end

/***
输出
a
b
d
e
***/

三. 参数

命令ruby file.rb arg1 arg2....中,可以通过ARGV来读取到该命令的参数,默认读取到的为字符,也可以将其转化为数字,从而进行运算操作。

str0 = ARGV[0]
str1 = ARGV[1]

puts "#{str0} + #{str1} = #{str0 + str1}"

/***
输出
1 + 2 = 12
***/
num0 = ARGV[0].to_i
num1 = ARGV[1].to_i

puts "#{num0} + #{num1} = #{num0 + num1}"

/***
输出
1 + 2 = 3
***/

四. 文件IO

1. 读取整个文件

filename = ARGV[0]
file = File.open(filename)
text = file.read
print text + "\n"
file.close

2. 逐行读取

如果只需要读取一个大文件里面的前几行,逐行读取会比较节省性能

filename = ARGV[0]
file = File.open(filename)
file.each_line do |line|
    print line
end
print "\n"
file.close

3. 带正则表达式的读取

如果需要匹配一个文件里面的一些字符,则可以带上正则表达式

pattern = Regexp.new(ARGV[0])

filename = ARGV[1]
file = File.open(filename)
file.each_line do |line|
    print line if pattern =~ line
end
print "\n"
file.close

下面这行命令,代表过滤含tbd字符串的文件,并打印出来

ruby LearnRuby.rb tbd BaseLinkMapResult.txt 

五. 引用库

通过require方法来引用库。

// LearnRuby.rb
def hello
    puts "Hello World"
end

// PrintRuby.rb

require './LearnRuby.rb'

hello()

// command
ruby PrintRuby.rb

六. 方法、变量

1. 方法

def hello
    puts "Hello World"
end

hello()

2. 变量

局部变量:x,全局变量:$x

// LearnRuby.rb
$x = 1
x = 1

// PrintRuby.rb
$x = 0
x = 0

require './LearnRuby.rb'

puts $x
puts x

// result
1
0

3. 常量

常量用全大写字母声明,与变量相似,但是修改常量会报警告。

TEST = 1
TEST = 2

puts TEST

// result
PrintRuby.rb:2: warning: already initialized constant TEST
PrintRuby.rb:1: warning: previous definition of TEST was here
2

4. 多重赋值

支持对应赋值语法

a, b, c = 1, 2

p [a, b, c]

// result
[1, 2, nil]

利用这个可以做出置换变量

a, b = 1, 2
a, b = b, a
p [a, b]

// result
[2,1]

七. 类

1. 定义

class Person
    attr_accessor :name

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

    def greet
        puts "Nice to meet u, #{self.name}"
    end
end

person = Person.new("Hoben")

person.greet()

// result
Nice to meet u, Hoben

attr_accessor代表着该类自动生成了getter和setter方法,initialize是初始化方法,里面可以放置参数,调用的时候,是object = Class.new()

如果需要自定义getter和setter方法,则需要这样来定义:

class Person
    # attr_accessor :name

    def name    # getter
        puts "It's Getter"
        @name
    end

    def name=(value)    # setter
        puts "It's Setter"
        @name = value
    end

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

    def greet(value)
        puts "Nice to meet u, #{value}"
    end
end

person = Person.new()

person.name = "NewName"

person.greet(person.name)

// result
It's Setter
It's Getter
Nice to meet u, NewName

注意:在自身类中self.name会调用getter,而@name则不会调用getter方法。(这个和OC很像)

2. public/private/protected

class Person
    def PublicMethod
        puts "Public"
    end

    public:PublicMethod

    def PrivateMethod
        puts "Private"
    end

    private:PrivateMethod
end

person = Person.new()

person.PublicMethod()

// 这里会报错
person.PrivateMethod()

其实和C++差不多,不多说了

3. 继承与扩展

继承用Son < Father来表示,用super来表示继承父类方法。

class Father
    def PublicMethod
        puts "Public"
    end

    public:PublicMethod

    def PrivateMethod
        puts "Private"
    end

    private:PrivateMethod

    def ProtectedMethod
        puts "Father Protected" 
    end

    protected:ProtectedMethod
end

class Son < Father
    def ProtectedMethod
        super()
        puts "Son Protected"
    end

    public:ProtectedMethod
end

son = Son.new()

son.ProtectedMethod()

// result
Father Protected
Son Protected

当然,也可以在原类的基础上去添加方法,使用扩展。

class String
    def expandMethod
        puts "It's Expand Method"
    end
end

s = String.new()
s.expandMethod()

4. 模块

模块Module和类Class相似,但又有点不同,是Ruby里面特有的用法,不同之处在于:

通过命名模块,我们可以在引用时省略模块名,直接一个include搞定,如:

// 下面两个一样
p Math::PI

include Math
p PI

如果有两个类,他们有共同的方法,但是又不希望将它们归为同一个Class的话,可以考虑采用模块:

module Common
    def commonMethod
        puts "Common"
    end

    Version = "1.0"
end

class SubClass1
    include Common

    def firstMethod
        puts "First"
    end
end

class SubClass2
    include Common

    def secondMethod
        puts "Second"
    end
end

first = SubClass1.new
second = SubClass2.new

first.commonMethod
first.firstMethod

second.commonMethod
second.secondMethod

include Common
puts Version

// result
Common
First
Common
Second
1.0

Extend方法可以使得单例类包含模块,并把模块的功能扩展到对象中。

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

str = "This is module:"

str.extend(Edition)

p str.edition(4)

// result
"This is module: No.4"

在上面的例子中,可以看到str扩展了一个Edition的module,在edition方法中,他提前设定了"xxx No.x"的字符串,当str扩展了这个module后,就可以先把自身打印出去,再套入输入的结果。

八. 逻辑运算

1. 比较有特色的逻辑

和C++的逻辑运算大同小异,讲一些比较有特色的:

// 当var不为空name = var,当var为空name = Ruby
name = var || "Ruby"

// 当ary为空item为nil,当ary不为空,item为ary[0]
item = ary && ary[0]

// [1, 10]
1..10

// [1, 10)
1...10

2. 重载

二元运算符:可以将运算符名作为方法名,从而重定义运算符。

class Point
    attr_accessor :x, :y

    def initialize(x=0, y=0)
        @x, @y = x, y
    end

    def position
        "(#{x}, #{y})"
    end

    def +(other)    #加法运算
        self.class.new(x + other.x, y + other.y)
    end

    def -(other)
        self.class.new(x - other.x, y - other.y)
    end
end

p1 = Point.new(1, 1)
p2 = Point.new(2, 2)

p (p1 - p2).position
p (p1 + p2).position

// result
"(-1, -1)"
"(3, 3)"

当然,一元运算符也可以重载

class Point
    attr_accessor :x, :y

    def initialize(x=0, y=0)
        @x, @y = x, y
    end

    def position
        "(#{x}, #{y})"
    end

    def +@
        dup     #返回自己的副本
    end

    def -@
        self.class.new(-x, -y)
    end

    def ~@
        self.class.new(y, x)
    end
end

p1 = Point.new(1, 2)
p (+p1).position
p (-p1).position
p (~p1).position

// result
"(1, 2)"
"(-1, -2)"
"(2, 1)"

甚至下标也可以重载

class Point
    attr_accessor :x, :y

    def initialize(x=0, y=0)
        @x, @y = x, y
    end

    def position
        "(#{x}, #{y})"
    end

    def [](index)
        return x if index == 0
        return y if index == 1
        return "Out of Range"
    end

    def []=(index, value)
        self.x = value if index == 0
        self.y = value if index == 1
        return "Out of Range"
    end
end

p1 = Point.new(1, 2)

p1[0] = 3
p1[1] = 4
p2 = Point.new(p1[0], p1[1])
p p2.position

// result
"(1, 2)"

九. 异常处理

begin ~ rescue ~ ensure ~ end来描述,需要抛出异常时,则调用raise方法,
类似于 try ~ catch ~ finally,调用throw抛出异常

begin
 有可能发生异常的处理
    raise...
rescue => 变量
 发生异常后的处理
ensure
 不管是否发生异常都希望执行的处理
end

运用到打开文件中,如果打开异常也需要关闭文件,则可以用该方法来处理。

file = File.open("sample.txt")
begin
    file.each do |file|
        file.each_line do |line|
            puts line
        end
    end
rescue Exception => e
    puts e.exception
ensure
    file.close
end

十. 块

块,即代码块,会在循环、替换算法中用到,也可以作为参数传入另一个块里面,和iOS的block有异曲同工之妙。

1. 替换算法

Array提供sort方法,用于从小到大去排序数组,但是如果我们要写cmp的话,就要自己去定义了。

array = ["d", "cc", "bbb", "aaaa"]

sorted = array.sort
sortedByLength = array.sort { |a, b|  a.length <=> b.length}

p sorted, sortedByLength

// result
["aaaa", "bbb", "cc", "d"]
["d", "cc", "bbb", "aaaa"]

根据上面的例子,可以看到,sort函数是根据字母的大小来判断的,而加入了cmp,则可以根据数组长度来判断。

其中,<=>表示

2. 传递块

def total(from, to)
    result = 0
    from.upto(to) do |num|
        if block_given?
            result += yield(num)
        else
            result += num
        end
    end
    return result
end

p total(1, 5)
p total(1, 5){|num| num ** 2}

// result
15
55

yield代表取块里面的值,block_given可以用于判断是否有传入块,from.upto(to)代表遍历from..to,也可以用(from..to).each来代替,可以看到,当传入块的时候,计算的结果为1^2+2^2+...+5^2

yield可以接收若干个参数,并使用这些参数。

def block_test
    yield()         # 0个块变量
    yield(1)        # 1个块变量
    yield(1, 2, 3)  # 2个块变量
end

p '通过|a|接收变量'

block_test do |a|
    p [a]
end

p '通过|a, b, c|接收变量'

block_test do |a, b, c|
    p [a, b, c]
end

// result
"通过|a|接收变量"
[nil]
[1]
[1]
"通过|a, b, c|接收变量"
[nil, nil, nil]
[1, nil, nil]
[1, 2, 3]
上一篇下一篇

猜你喜欢

热点阅读